Form
// @namespace Form
import { Form } from 'rcfm'
Custom Types
@typedef {Object} FormInstance
@description - 表单实例
@prop {ReactiveInstance} reactive
@typedef {Object} FormMemberType
@description - 表单成员类型
@prop {string} type - 类型名称
@prop {ContextHook[]} [hooks] - 钩子定义数组
@prop {Function} [collect = reactive#collect] - 自定义搜集该类型成员状态函数
@prop {Function} [seed = reactive#seed] - 自定义填充该类型成员属性设定值函数
@prop {Object} [schema = {}]
@prop {ReactiveMemberPropSchema[]} [schema.props] - 成员属性定义
@prop {ReactiveMemberPropSchema} [schema.fallback = ReactiveMemberFallbackPropSchema] - 成员属性缺省定义
@prop {Object} [reference = {}]
@prop {Function} [reference.parse = reactive#schema.reference.parse] - 自定义成员路径转唯一标识及属性名称方法
@prop {Function} [reference.stringify = reactive#schema.reference.stringify] - 自定义成员唯一标识及属性名称转路径方法
@prop {string|string[]} [group] - 分组名称
@prop {Function} [providers = Form.providers] - 可引用成员过滤函数
入参为一个 DependencyRelier 和一个自定义 options 对象,应返回 DependencyProvider 构成的数组或 null
@prop {Function} [validators = Form.validators] - 可使用校验方法过滤函数
入参为一个 DependencyProvider 或 DependencyRelier,和一个自定义 options 对象,应返回 ValidatorAlgorithm 构成的数组或 null
Builtin Member Types
Fieldset
输入项集合,用来包裹表单输入项成员及子表单成员等。
// @example
const {reactive} = Form.create()
const userInfo = reactive.add({props: {
type: 'Fieldset',
name: 'user',
label: 'User Information',
description: 'User information is necessary in this form, since...'
}})
const orderInfo = reactive.add({props: {
type: 'Fieldset',
name: 'order',
label: 'Order Information',
description: 'Order information is necessary in this form, since...'
}})
reactive.add({parentId: userInfo, props: {
type: 'TextField',
name: 'username',
label: 'Your name',
placeholder: 'E.g, Jerry'
}})
reactive.add({parentId: orderInfo, props: {
type: 'CheckboxField',
name: 'goods',
label: 'Ordered Goods',
options: [{value: 'mac', label: 'Mac'}, {value: 'laptop', label: 'Laptop'}]
}})
Fieldset Enabled Hooks
[
Reactive.hooks.use('ENABLE_SCHEMA_DEFAULT'),
Reactive.hooks.use('ENABLE_SCHEMA_VALIDATION'),
]
Fieldset Property Schemas
[{
prop: 'name',
default: () => Reactive.guid(),
schemable: false,
calculable: false,
validation: [{ presence: true }, { dataType: 'String' }, { unique: true }]
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'label',
default: '',
schemable: false,
calculable: false,
validation: [{ dataType: 'String' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'description',
default: '',
schemable: false,
calculable: false,
validation: [{ dataType: 'String' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}]
Field Types
CheckboxField
& MultipleSelectField
复选框和多选菜单。
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
reactive.add({parentId: fieldset, props: {
type: 'CheckboxField',
name: 'goods',
label: 'Ordered Goods',
options: [{value: 'mac', label: 'Mac'}, {value: 'laptop', label: 'Laptop'}]
}})
reactive.add({parentId: fieldset, props: {
type: 'MultipleSelectField',
name: 'pereferences',
label: 'Pereferences',
options: [{value: 'high_dpi', label: 'High DPI'}, {value: 'slim', label: 'Slim'}]
}})
CheckboxField & MultipleSelectField Enabled Hooks
[
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Fieldset' }),
Reactive.hooks.use('ENABLE_SCHEMA_DEFAULT'),
Field.hooks.use('ENABLE_VALUE_CALCULATION'),
Reactive.hooks.use('ENABLE_SCHEMA_VALIDATION'),
Field.hooks.use('ENSURE_VALUE_WITHIN_OPTIONS'),
Field.hooks.use('ENABLE_VALUE_VALIDATION'),
]
CheckboxField & MultipleSelectField Property Schemas
[{
prop: 'name',
default: () => Reactive.guid(),
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }, { unique: true }]
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'label',
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'value',
default: null,
schemable: false,
calculable: false,
rawValidation: null,
validation: [{dataType: 'Array'}],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'options',
default: [{ label: guid(), value: guid() }],
schemable: false,
calculable: false,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'Array' }, function(member) {
// A function ensures each option is unique.
}],
}, {
prop: 'editable',
default: true,
schemable: true,
calculable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'visible',
default: true,
schemable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'validation',
default: null,
schemable: true,
calculable: true,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
validation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
}, {
prop: 'calculation',
default: null,
schemable: true,
calculable: true,
validation: null,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [function(member) {
// A function to ensure the defined calculation is supported by the Calculator module.
}],
}]
NumberField
数字输入。
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
reactive.add({parentId: fieldset, props: {
type: 'NumberField',
name: 'age',
label: 'Age',
placeholder: 'E.g, 23'
}})
NumberField Enabled Hooks
[
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Fieldset' }),
Reactive.hooks.use('ENABLE_SCHEMA_DEFAULT'),
Field.hooks.use('ENABLE_VALUE_CALCULATION'),
Reactive.hooks.use('ENABLE_SCHEMA_VALIDATION'),
Field.hooks.use('ENABLE_VALUE_VALIDATION')
]
NumberField Property Schemas
[{
prop: 'name',
default: () => Reactive.guid(),
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }, { unique: true }]
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'label',
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'placeholder',
schemable: false,
calculable: false,
rawValidation: null,
validation: [{dataType: 'String'}],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'value',
default: null,
schemable: false,
calculable: false,
rawValidation: null,
validation: [{dataType: 'Number'}],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'editable',
default: true,
schemable: true,
calculable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'visible',
default: true,
schemable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'validation',
default: null,
schemable: true,
calculable: true,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
validation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
}, {
prop: 'calculation',
default: null,
schemable: true,
calculable: true,
validation: null,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [function(member) {
// A function to ensure the defined calculation is supported by the Calculator module.
}],
}]
TextField
& MultilineTextField
单行文本和多行文本。
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
reactive.add({parentId: fieldset, props: {
type: 'TextField',
name: 'username',
label: 'User Name',
placeholder: 'E.g, Jim'
}})
reactive.add({parentId: fieldset, props: {
type: 'MultilineTextField',
name: 'description',
label: 'Description',
placeholder: 'E.g, Jim is a...'
}})
TextField & MultilineTextField Enabled Hooks
[
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Fieldset' }),
Reactive.hooks.use('ENABLE_SCHEMA_DEFAULT'),
Field.hooks.use('ENABLE_VALUE_CALCULATION'),
Reactive.hooks.use('ENABLE_SCHEMA_VALIDATION'),
Field.hooks.use('ENABLE_VALUE_VALIDATION')
]
TextField & MultilineTextField Property Schemas
[{
prop: 'name',
default: () => Reactive.guid(),
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }, { unique: true }]
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'label',
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'placeholder',
schemable: false,
calculable: false,
rawValidation: null,
validation: [{dataType: 'String'}],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'value',
default: null,
schemable: false,
calculable: false,
rawValidation: null,
validation: [{dataType: 'String'}],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'editable',
default: true,
schemable: true,
calculable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'visible',
default: true,
schemable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'validation',
default: null,
schemable: true,
calculable: true,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
validation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
}, {
prop: 'calculation',
default: null,
schemable: true,
calculable: true,
validation: null,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [function(member) {
// A function to ensure the defined calculation is supported by the Calculator module.
}],
}]
RadioField
& SingleSelectField
单选框和单选菜单。
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
reactive.add({parentId: fieldset, props: {
type: 'RadioField',
name: 'delivery',
label: 'Delivery',
options: [{value: 'express', label: 'Express'}, {value: 'yuantong', label: 'Yuantong'}]
}})
reactive.add({parentId: fieldset, props: {
type: 'SingleSelectField',
name: 'payment',
label: 'Payment',
options: [{value: 'wechat', label: '微信'}, {value: 'alipay', label: '支付宝'}]
}})
RadioField & SingleSelectField Enabled Hooks
[
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Fieldset' }),
Reactive.hooks.use('ENABLE_SCHEMA_DEFAULT'),
Field.hooks.use('ENABLE_VALUE_CALCULATION'),
Reactive.hooks.use('ENABLE_SCHEMA_VALIDATION'),
Field.hooks.use('ENSURE_VALUE_WITHIN_OPTIONS'),
Field.hooks.use('ENABLE_VALUE_VALIDATION'),
]
RadioField & SingleSelectField Property Schemas
[{
prop: 'name',
default: () => Reactive.guid(),
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }, { unique: true }]
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'label',
schemable: false,
calculable: false,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'String' }],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'value',
default: null,
schemable: false,
calculable: false,
rawValidation: null,
validation: [{dataType: 'String'}],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'options',
default: [{ label: guid(), value: guid() }],
schemable: false,
calculable: false,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: null,
validation: [{ presence: true }, { dataType: 'Array' }, function(member) {
// A function ensures each option is unique.
}],
}, {
prop: 'editable',
default: true,
schemable: true,
calculable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'visible',
default: true,
schemable: true,
rawValidation: [{ presence: true }, { dataType: 'Boolean' }],
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'validation',
default: null,
schemable: true,
calculable: true,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
validation: [{ dataType: 'Array' }, function(member) {
// A function to ensure all defined validations are supported by the Validator module.
}],
}, {
prop: 'calculation',
default: null,
schemable: true,
calculable: true,
validation: null,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
rawValidation: [function(member) {
// A function to ensure the defined calculation is supported by the Calculator module.
}],
}]
Subform Types
Subform
子表单。
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
reactive.add({parentId: fieldset, props: {
type: 'Subform',
name: 'addresses',
label: 'Addresses'
}})
Subform Enabled Hooks
[
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Fieldset' }),
Reactive.hooks.use('ENABLE_SCHEMA_DEFAULT'),
Reactive.hooks.use('ENABLE_SCHEMA_VALIDATION'),
]
Subform Property Schemas
[{
prop: 'name',
default: () => Reactive.guid(),
schemable: false,
calculable: false,
validation: [{ presence: true }, { dataType: 'String' }, { unique: true }]
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'label',
schemable: false,
calculable: false,
validation: [{ presence: true }, { dataType: 'String' }],
default: <global_i18n_defination>,
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'editable',
default: true,
schemable: true,
calculable: true,
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}, {
prop: 'visible',
default: true,
schemable: true,
validation: [{ presence: true }, { dataType: 'Boolean' }],
label: <global_i18n_defination>,
placeholder: <global_i18n_defination>,
hint: <global_i18n_defination>,
}]
SubformFieldset
子表单输入项集合,用于包裹各子表单输入项。
当 SubformFieldset
被创建后, 会克隆进一组其它 SubformFieldset
中已存在的 Subform*Field
; 当 SubformFieldset
中被添加进 Subform*Field
, 其它 SubformFieldset
也都会被复制进一个属性设定值相同的 Subform*Field
; 当 SubformFieldset
中的 Subform*Field
被删除,其它 SubformFieldset
中同一 order
位置 的 Subform*Field
也都会被删除; 当 Subform*Field
除了 value
外的属性设定值变更, 其它 SubformFieldset
中同一 order
位置的 Subform*Field
的同一属性都会被设定为相同的值。
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
const subform = reactive.add({parentId: fieldset, props: {
type: 'Subform',
name: 'addresses',
label: 'Addresses'
}})
const subformFieldset = reactive.add({parentId: subform, props: {
type: 'SubformFieldset'
}})
reactive.add({parentId: subformFieldset, props: {
type: 'SubformSingleSelectField',
label: 'Province',
options: [{value: 'changchun', label: '长春'}, {value: 'jilin', label: '吉林'}]
}})
SubformFieldset Enabled Hooks
[
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Subform' })
]
SubformFieldset Enabled Schemas
无。
Subform*Field
// @example
const {reactive} = Form.create()
const fieldset = reactive.add({props: {type: 'Fieldset'}})
const subform = reactive.add({parentId: fieldset, props: {
type: 'Subform',
name: 'addresses',
label: 'Addresses'
}})
const subformFieldset = reactive.add({parentId: subform, props: {
type: 'SubformFieldset'
}})
reactive.add({parentId: subformFieldset, props: {
type: 'SubformSingleSelectField',
label: 'Province',
options: [{value: 'changchun', label: '长春'}, {value: 'jilin', label: '吉林'}]
}})
Subform*Field Enabled Hooks
SubformField
类型基于对应的 Field
类型动态生成,多数 hooks 与原始类型相同,除了使用
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'SubformFieldset'})
替代了
Reactive.hooks.use('BLOCK_INVALID_PARENT', { accept: 'Fieldset'})
Subform*Field Property Schemas
SubformField
类型基于对应的 Field
类型动态生成,属性定义与原始类型相同。
Class Methods
.create()
创建一个表单实例。
// Form.create()
// @returns {FormInstance}
// @example
const {reactive} = Form.create()
.group()
按分组查询表单成员。
// Form.group(group)
// @param {string | undefined} group - 分组名称
// @returns {null | FormMemberType[]} - 返回匹配的表单成员类型定义
// @example
const definations = Form.group('Field') // FormMemberType[]
.install()
注册一个表单成员类型,该方法包装了 reactive#install()
,但只在表单实例创建前调用有效。
// Form.install(type)
// @param {FormMemberType} type
// @returns {undefined}
// @example
Form.install({
group: 'custom',
type: 'ACustomType',
hooks: [...],
schema: {
props: [...],
reference: {
parse(provider, relier) {...},
stringify(provider, relier) {...}
}
},
seed(member, props) {...},
collect(member) {...},
// 限定该类型成员可引用范围
providers(relier, options) {
// this 指向 ReactiveInstance
let {id, prop} = relier
// 以只能引用同辈成员的 value 属性为例
let siblings = this.family.sibling({id})
if (!siblings) { return [] }
return siblings.map((s) => ({id: s.id, prop: 'value'}))
},
// 限定可使用校验方法范围
validators(target, options) {
// this 指向 ReactiveInstance
let {id, prop} = target
// 以只能使用应用于 String 数据格式的校验方法为例
return this.validator.for('String')
}
})
.providers()
查询某表单成员可引用范围。 对于注册时未设定 providers
的类型(如内置引擎默认集成的各输入项类型), 调用该方法将返回默认引用范围。 默认可被引用的成员是所有 Fieldset
子级中含有 value
属性且不与被查询成员产生循环引用的成员, 默认可被引用的属性则是 value
。
// Form.providers(reactive, relier)
// @param {ReactiveInstance} reactive
// @param {DependencyRelier} member
// @returns {DependencyProvider[] | null}
// @example
Form.providers(reactive, {id: textFieldId, prop: 'value'})
.uninstall()
移除一个已注册的表单成员类型,只在创建表单实例前有效。
// Form.uninstall(name)
// @param {string} name - 成员类型名称
// @returns {undefined}
// @example
Form.uninstall('ACustomType')
.validators()
查询某表单成员可使用的校验方法范围。 对于注册时未设定 validators
的类型(如内置引擎默认集成的各输入项类型), 调用该方法将返回默认的可用校验方法范围。 默认范围的匹配规则是,如果 schema
定义中 value
属性的 validation
指定了 dataType
, 则返回所有可用于该 dataType
的校验方法,否则只返回 presence
校验方法。
// Form.validators(reactive, member)
// @param {ReactiveInstance} reactive
// @param {DependencyProvider | DependencyRelier} member
// @returns {ValidatorAlgorithm[] | null}
// @example
Form.validators(reactive, {id: textFieldId, prop: 'value'})