English
fs-form
About 1734 wordsAbout 6 min
Introduction
fs-form is modeled after Element UI Form, used to collect, validate, and submit form data. It consists of fs-form (the form container), fs-form-item (a form item, including label, error message, and required marker), and form item content controls (such as fs-input). It supports unified or per-item validation rules (required, pattern, min/max/len, whitespace, custom validator), supports triggers (blur / change / submit) to control when validation runs, and supports multiple field layouts (left-right / top-bottom, left-aligned / center-aligned, etc.).
UI design: https://www.figma.com/design/ULbC0RoBVE9UHOPZxrpLIz/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%9F%BA%E7%A1%80%E7%BB%84%E4%BB%B6%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83?node-id=6895-99499&p=f
Usage
For local registration, configure it in the page's index.json (fs-form depends on fs-form-item, and the form item content control must be imported separately, e.g. fs-form-input):
"usingComponents": {
"fs-form": "/avaui-sub/fs-form/index",
"fs-form-item": "/avaui-sub/fs-form/fs-form-item/index",
"fs-form-input": "/avaui-sub/fs-form/fs-form-input/index"
}PWC (custom component/plugin) usage: only the usingComponents registration follows the format below (the avaComponent:// protocol); other usage is identical to local registration.
"usingComponents": {
"fs-form": "avaComponent://avaui-sub/fs-form/index",
"fs-form-item": "avaComponent://avaui-sub/fs-form/fs-form-item/index",
"fs-form-input": "avaComponent://avaui-sub/fs-form/fs-form-input/index"
}Code Demos
The following sections are in the same order as the demo preview for easy cross-reference.
1. Basic Usage
Bind form data via model and validation rules via rules; the prop of fs-form-item corresponds to a model field name. On submit, obtain the form instance via selectComponent and call validate() and getValue().
Multiple form item types are supported:
- Text input: use the
fs-form-inputcomponent, supportingtype="text"(single line) andtype="textarea"(multi-line text area) - Radio: use the
fs-form-radiocomponent;valueis a single value - Checkbox: use the
fs-form-checkboxcomponent;valueis an array, and validation requirestype: 'array'
2. Alignment (fieldAlign)
Use the fieldAlign of fs-form to set the layout of all form items uniformly, or override it per item via the fieldAlign of fs-form-item. Optional values: left (left-right, left-aligned), top_and_bottom (top-bottom), center (left-right, center-aligned), whole_left (left-right, content immediately follows the label).
To customize the form's inner padding, set clear-spacing-h / clear-spacing-v on fs-form-item to remove the default horizontal/vertical padding and margin respectively.
3. Form Validation: Required and Format
Rules align with async-validator, supporting required, message, pattern (regex; a string is converted to a RegExp), min/max/len (length or numeric limits), and whitespace: true (disallows pure whitespace).
4. Validation Trigger (trigger)
Consistent with Element UI, supports trigger: 'blur' (on blur), trigger: 'change' (on value change), and trigger: 'submit' (only on submit). If trigger is omitted, the rule participates in validation on blur, change, and submit. All rules are always validated on submit, regardless of trigger.
5. Custom Validation (validator)
Supports custom rules, Promise syntax only: resolve() means pass, reject(error) or reject([error, ...]) means fail (error can be a string or an Error).
6. Custom Form Item Content
fs-form-item updates validation state by capturing the change and blur events of its slot content. Therefore, custom form item content components must follow these conventions:
- Props: accept a
valueproperty for display. - Events:
- Trigger a
changeevent on value change;detailmust contain{ value: newValue }. - Trigger a
blurevent on blur (optional, used for blur validation). - Important: events must enable bubbling with
bubbles: trueandcomposed: trueso thatfs-form-itemcan listen for them.
- Trigger a
Custom Component Example (my-mood)
// my-mood/index.js
Component({
properties: { value: String },
methods: {
onTap(e) {
const val = e.currentTarget.dataset.val;
this.setData({ value: val });
// Key: trigger the change event with bubbles: true so fs-form-item can capture it
this.triggerEvent('change', { value: val }, { bubbles: true, composed: true });
}
}
});7. Wrapper Scenario (formId)
When using a wrapper component to wrap fs-form-item, the WeChat mini-program relations mechanism may fail, preventing the parent-child relationship from being established. In this case, use the formId property as a page-level registry fallback:
- Set a unique
formIdonfs-form - Pass the same
formIdthrough to eachfs-form-item(or wrapping wrapper)
This way, even if relations fail, the corresponding form instance can still be located via the page-level registry.
<fs-form formId="myForm" model="{{formModel}}" rules="{{formRules}}">
<form-item-wrapper formId="myForm" prop="name" label="Name" />
<form-item-wrapper formId="myForm" prop="email" label="Email" />
</fs-form>8. Wrapper Scenario (catchchange to Prevent Duplicate Events)
When using a wrapper component to wrap form item content components (such as fs-form-file, fs-form-input, etc.), if the wrapper layer needs to handle change logic itself and re-trigger the change event, you must use catchchange instead of bindchange to listen to the child component's change.
Cause
The change event of form item content components enables bubbles: true and composed: true by default so that fs-form-item can listen for it. If you use bindchange, the event continues to bubble up to fs-form-item; meanwhile, the wrapper layer re-triggers a change event itself via triggerEvent('change', ...), causing fs-form-item to receive 2 change events, which may lead to anomalies.
Correct Usage
<!-- Incorrect: causes fs-form-item to receive 2 change events -->
<fs-form-file bindchange="onFileChange" />
<!-- Correct: use catchchange to stop bubbling, letting the wrapper decide how to trigger -->
<fs-form-file catchchange="onFileChange" />// wrapper component
Component({
methods: {
onFileChange(e) {
// Handle the file change logic
const newValue = e.detail.value;
// The wrapper decides when to trigger the change event, passing bubbles: true so fs-form-item can listen
this.triggerEvent('change', { value: newValue }, { bubbles: true, composed: true });
}
}
});Scope of Application
This rule applies to all wrapper scenarios for form item content components, including but not limited to:
fs-form-filefs-form-inputfs-form-radiofs-form-checkboxfs-form-date
Core Principle
When wrapping, use catchchange to stop the child component's change event from bubbling, and let the wrapper control when and how the change event is triggered.
API
fs-form Properties
| Parameter | Description | Type | Optional Values | Default |
|---|---|---|---|---|
| formId | Form ID, used for page-level registry lookup | String | — | '' |
| model | Form data object | Object | — | {} |
| rules | Validation rules, keyed by prop | Object | — | {} |
| fieldAlign | Overall layout of form items | String | left / top_and_bottom / center / whole_left | left |
fs-form Events
| Event Name | Description | Callback |
|---|---|---|
| change | Triggered when a form field changes; the event enables bubbles: true and composed: true | { model, prop, value, type:'form' } |
Note: Due to the bubbling mechanism, a single field change triggers at least 2 change events: one is the field's own change event, and another is the form's change event. Use type to distinguish the form's change event.
fs-form Methods
Obtain the instance via selectComponent and call:
| Method Name | Description | Return Value |
|---|---|---|
| getValue() | Get the current form data | Object |
| validate() | Validate the entire form | Promise<>; resolve means pass, reject means validation failed |
| clearValidate(props?) | Clear validation state; clears all if no argument, or the specified props if an array is passed | void |
fs-form-item Properties
| Parameter | Description | Type | Optional Values | Default |
|---|---|---|---|---|
| formId | Form ID, used for page-level registry lookup | String | — | '' |
| prop | Field name corresponding to the form model | String | — | '' |
| label | Label text | String | — | '' |
| required | Whether required (shows an asterisk) | Boolean | — | false |
| fieldAlign | Layout of this item, overrides form's fieldAlign | String | left / top_and_bottom / center / whole_left | '' |
| rules | Item-specific validation rules, takes priority over form.rules[prop] | Array | See "Validation Rule Fields" below | [] |
| clearSpacingH | Whether to clear the default horizontal padding/margin of the label and value areas | Boolean | — | false |
| clearSpacingV | Whether to clear the default vertical padding of the label and value areas | Boolean | — | false |
Validation Rule Fields (single rule)
Aligned with Element UI / async-validator:
| Field | Description | Type |
|---|---|---|
| required | Whether required | Boolean |
| message | Validation failure message | String |
| pattern | Regex; a string is converted to RegExp | RegExp / String |
| min / max / len | Length or numeric limits, distinguished by type or value type | Number |
| whitespace | When true, pure whitespace is not allowed | Boolean |
| trigger | Trigger timing: 'blur' / 'change' / 'submit', or an array | String / Array |
| validator | Custom validation, Promise syntax only: (rule, value, source, options) => Promise | Function |
