重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
b2c-forms by salesforcecommercecloud/b2c-developer-tooling
npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-forms此技能指导您使用 SFRA 模式在 Salesforce B2C Commerce 中创建带验证的表单。
B2C Commerce 表单由三部分组成:
表单定义在 cartridge 的 forms 目录中:
/my-cartridge
/cartridge
/forms
/default # 默认区域设置
profile.xml
contact.xml
/de_DE # 德语特定(可选)
address.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>
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 类型 | 描述 | 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 | 一般验证失败 |
有关完整的字段属性、分组、列表和验证模式,请参阅 Form XML Reference。
'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(); // 重置之前的值
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();
}
// 访问表单值
var email = form.email.value;
var firstName = form.firstName.value;
// 处理并保存数据
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();
});
<form action="${pdict.actionUrl}" method="POST" name="profile-form"
class="form-horizontal" data-action="${URLUtils.url('Profile-Submit')}">
<!-- CSRF 令牌 -->
<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
route:BeforeComplete 进行数据库操作有关全面的表单模式:
每周安装量
62
代码仓库
GitHub 星标数
34
首次出现
2026年2月21日
安全审计
安装于
github-copilot57
codex54
cursor54
opencode53
amp52
kimi-cli52
This skill guides you through creating forms with validation in Salesforce B2C Commerce using the SFRA patterns.
B2C Commerce forms consist of three parts:
Forms are defined in the cartridge's forms directory:
/my-cartridge
/cartridge
/forms
/default # Default locale
profile.xml
contact.xml
/de_DE # German-specific (optional)
address.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>
| Type | Description | HTML Input |
|---|---|---|
string | Text input | <input type="text"> |
integer | Whole number | <input type="number"> |
number | Decimal number | <input type="number"> |
boolean |
| Attribute | Purpose | Example |
|---|---|---|
formid | Field identifier (required) | formid="email" |
label | Resource key for label | label="form.email.label" |
type | Data type (required) | type="string" |
mandatory |
| Attribute | When Triggered |
|---|---|
missing-error | Mandatory field is empty |
parse-error | Value doesn't match regexp or type |
range-error | Value outside min/max range |
value-error | General validation failure |
See Form XML Reference for complete field attributes, groups, lists, and validation patterns.
'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();
});
<form action="${pdict.actionUrl}" method="POST" name="profile-form"
class="form-horizontal" data-action="${URLUtils.url('Profile-Submit')}">
<!-- CSRF Token -->
<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>
Form labels and errors use resource bundles:
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
route:BeforeComplete for database operationsFor comprehensive form patterns:
Weekly Installs
62
Repository
GitHub Stars
34
First Seen
Feb 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
github-copilot57
codex54
cursor54
opencode53
amp52
kimi-cli52
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
123,700 周安装
| Checkbox |
<input type="checkbox"> |
date | Date value | <input type="date"> |
| Required field |
mandatory="true" |
max-length | Max string length | max-length="100" |
min-length | Min string length | min-length="8" |
regexp | Validation pattern | regexp="^\d{5}$" |