关于 b2c-forms
面向 Salesforce B2C Commerce 开发者的表单技能,介绍如何按 SFRA 模式创建和验证表单,涵盖 XML 定义、控制器处理、ISML 模板、本地化及提交保护。
主要功能
- 01在 XML 中定义字段和验证规则
- 02在 SFRA 控制器中处理表单
- 03使用 ISML 模板呈现表单
- 04本地化标签和错误消息
- 05实施 CSRF 防护和服务器端验证
适用场景
- 01创建个人资料或联系表单
- 02验证提交的表单数据
- 03构建 AJAX 表单提交
- 04支持本地化的表单标签和错误
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ salesforcecommercecloud/ b2c-developer-tooling --skill b2c-forms安装后在 Claude Code 中输入/b2c-forms确认已加载。
附带文件evals/trigger-evals.jsonreferences/FORM-XML.md
详细介绍
表单技能
此技能将指导你使用 SFRA 模式在 Salesforce B2C Commerce 中创建带验证的表单。
概述
B2C Commerce 表单由三部分组成:
- 表单定义 - 定义字段、验证和操作的 XML 文件
- 控制器逻辑 - 服务端表单处理与提交处理
- 模板 - 用于渲染 HTML 表单的 ISML 模板
文件位置
表单位于 cartridge 的 forms 目录中:
/my-cartridge
/cartridge
/forms
/default # Default locale
profile.xml
contact.xml
/de_DE # German-specific (optional)
address.xml
表单定义(XML)
基本结构
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.demandware.com/xml/form/2008-04-19">
<field formid="email" label="form.email.label" type="string"
mandatory="true" max-length="50"
regexp="^[\w.%+-]+@[\w.-]+\.\w{2,6}$"
parse-error="form.email.invalid"/>
<field formid="password" label="form.password.label" type="string"
mandatory="true" min-length="8" max-length="255"
missing-error="form.password.required"/>
<field formid="rememberMe" label="form.remember.label" type="boolean"/>
<action formid="submit" valid-form="true"/>
<action formid="cancel" valid-form="false"/>
</form>
字段类型
| 类型 | 描述 | HTML 输入 |
|---|---|---|
string | 文本输入 | <input type="text"> |
integer | 整数 | <input type="number"> |
number | 小数 | <input type="number"> |
boolean | 复选框 | <input type="checkbox"> |
date | 日期值 | <input type="date"> |
关键字段属性
| 属性 | 用途 | 示例 |
|---|---|---|
formid | 字段标识符(必填) | formid="email" |
label | 标签的资源键 | label="form.email.label" |
type | 数据类型(必填) | type="string" |
mandatory | 必填字段 | mandatory="true" |
max-length | 最大字符串长度 | max-length="100" |
min-length | 最小字符串长度 | min-length="8" |
regexp | 验证模式 | regexp="^\d{5}$" |
验证错误消息
| 属性 | 触发时机 |
|---|---|
missing-error | 必填字段为空 |
parse-error | 值与正则表达式或类型不匹配 |
range-error | 值超出最小值/最大值范围 |
value-error | 常规验证失败 |
完整的字段属性、分组、列表和验证模式,请参阅 表单 XML 参考。
控制器逻辑(SFRA)
渲染表单
'use strict';
var server = require('server');
var csrfProtection = require('*/cartridge/scripts/middleware/csrf');
server.get('Show',
csrfProtection.generateToken,
function (req, res, next) {
var form = server.forms.getForm('profile');
form.clear(); // Reset previous values
res.render('account/profile', {
profileForm: form
});
next();
}
);
module.exports = server.exports();
处理表单提交
server.post('Submit',
server.middleware.https,
csrfProtection.validateAjaxRequest,
function (req, res, next) {
var form = server.forms.getForm('profile');
if (!form.valid) {
res.json({
success: false,
fields: getFormErrors(form)
});
return next();
}
// Access form values
var email = form.email.value;
var firstName = form.firstName.value;
// Process and save data
this.on('route:BeforeComplete', function () {
var Transaction = require('dw/system/Transaction');
Transaction.wrap(function () {
customer.profile.email = email;
customer.profile.firstName = firstName;
});
});
res.json({ success: true });
next();
}
);
function getFormErrors(form) {
var errors = {};
Object.keys(form).forEach(function (key) {
if (form[key] && form[key].error) {
errors[key] = form[key].error;
}
});
return errors;
}
预填充表单
server.get('Edit', function (req, res, next) {
var form = server.forms.getForm('profile');
form.clear();
var profile = req.currentCustomer.profile;
form.firstName.value = profile.firstName;
form.lastName.value = profile.lastName;
form.email.value = profile.email;
res.render('account/editProfile', { profileForm: form });
next();
});
模板(ISML)
基本表单模板
<form action="${pdict.actionUrl}" method="POST" name="profile-form"
class="form-horizontal" data-action="${URLUtils.url('Profile-Submit')}">
<input type="hidden" name="${pdict.csrf.tokenName}" value="${pdict.csrf.token}"/>
<div class="form-group ${pdict.profileForm.email.mandatory ? 'required' : ''}">
<label for="email" class="form-control-label">
${Resource.msg('form.email.label', 'forms', null)}
</label>
<input type="email"
id="email"
name="email"
class="form-control ${pdict.profileForm.email.error ? 'is-invalid' : ''}"
value="${pdict.profileForm.email.value || ''}"
<isif condition="${pdict.profileForm.email.mandatory}">required</isif>
maxlength="${pdict.profileForm.email.maxLength || 50}"/>
<isif condition="${pdict.profileForm.email.error}">
<div class="invalid-feedback">${pdict.profileForm.email.error}</div>
</isif>
</div>
<button type="submit" class="btn btn-primary">
${Resource.msg('button.submit', 'forms', null)}
</button>
</form>
本地化
表单标签和错误消息使用资源包:
forms.properties:
form.email.label=Email Address
form.email.required=Email is required
form.email.invalid=Please enter a valid email address
form.password.label=Password
button.submit=Submit
forms_de_DE.properties:
form.email.label=E-Mail-Adresse
form.email.required=E-Mail ist erforderlich
最佳实践
- 提交表单时始终使用 CSRF 保护
- 显示表单前清除表单,以重置状态
- 标签和错误消息使用资源键(本地化)
- 即使使用客户端验证,也要在服务端验证
- 数据库操作使用
route:BeforeComplete - AJAX 表单提交时返回 JSON
详细参考
如需了解完整的表单模式:
- 表单 XML 参考 - 完整的 XML 架构、验证模式和示例
评论
支持 Markdown