zent
Version:
一套前端设计语言和基于React的实现
192 lines (161 loc) • 4.56 kB
text/typescript
import { BehaviorSubject } from 'rxjs';
import identity from '../../../utils/identity';
import { BasicModel } from './basic';
import { Some, None, or, isSome, get } from '../maybe';
import { ValidateOption } from '../validate';
import isNil from '../../../utils/isNil';
import uniqueId from '../../../utils/uniqueId';
import { FIELD_ID } from './is';
import type { FieldBuilder } from '../builders';
import { createSentinelSubject } from './sentinel-subject';
import { createFormValidatorRuntimeError } from '../error';
export interface INormalizeBeforeSubmit<A, B> {
(a: A): B;
}
class FieldModel<Value> extends BasicModel<Value> {
/**
* @internal
*/
[FIELD_ID]!: boolean;
protected readonly _displayName = 'FieldModel';
readonly _value$ = new BehaviorSubject(this.defaultValue);
readonly _valid$ = new BehaviorSubject(true);
/**
* 当前 `FieldModel` 对象的 builder 对象,仅在 `Model` 模式下可用。
*/
readonly builder?: FieldBuilder<Value>;
isTouched = false;
/**
* 输入法的 composition 状态
*/
isCompositing = false;
/**
* 用于表单提交前格式化 `Field` 值的回调函数
*/
normalizeBeforeSubmit: INormalizeBeforeSubmit<Value, any> = identity;
owner: BasicModel<any> | null = null;
/** @internal */
constructor(private readonly defaultValue: Value) {
super(uniqueId('field-'));
}
get value$() {
return this._value$;
}
get valid$() {
return this._valid$;
}
/**
* @internal
*
* The same as value$, but without warning
*/
_getValue$() {
return this._value$;
}
/**
* @internal
*
* The same as value$, but without warning
*/
_getValid$() {
return this._valid$;
}
/**
* 重置 `Field` 为初始值,初始值通过 `initialize` 设置;如果初始值不存在就使用默认值
*/
reset() {
this._getValue$().next(or(this.initialValue, () => this.defaultValue));
}
/**
* 清除 `Field` 的初始值,并将当前值设置为默认值
*/
clear() {
this.initialValue = None();
this._getValue$().next(this.defaultValue);
}
clearError() {
this.error$.next(null);
}
/**
* 设置 `Field` 为指定的值,同时会设置初始值
* @param value 要设置的值
*/
initialize(value: Value) {
this.initialValue = Some(value);
this._getValue$().next(value);
}
getRawValue() {
return this._getValue$().getValue();
}
/**
* 获取用于表单提交的值
*/
getSubmitValue() {
const { normalizeBeforeSubmit } = this;
return normalizeBeforeSubmit(this._getValue$().getValue());
}
/**
* 执行 `Field` 的校验规则
* @param option 执行校验规则的参数
*/
validate(option = ValidateOption.Default) {
return this.triggerValidate(option).then(
maybeError => {
this._getValid$().next(isNil(maybeError));
return maybeError;
},
(err: any) => {
throw createFormValidatorRuntimeError(err);
}
);
}
/**
* 更新 `Field` 的值
* @param value 要设置的值
*/
patchValue(value: Value) {
this._getValue$().next(value);
}
/**
* `Field` 的值是否没有改变过,如果存在初始值会和初始值比较,否则和默认值比较
*/
pristine() {
const value = this._getValue$().getValue();
if (isSome(this.initialValue)) {
return value === get(this.initialValue);
}
return value === this.defaultValue;
}
/**
* `Field` 的值是否改变过,如果存在初始值会和初始值比较,否则和默认值比较
*
* `dirty === !pristine`
*/
dirty() {
return !this.pristine();
}
/**
* 用户是否操作过 `Field`,一般是在 `blur` 事件后设置,部分 `Field` 没有 `blur` 事件可能会在 `change` 的时候设置这个状态
*/
touched() {
return this.isTouched;
}
dispose() {
super.dispose();
// Close all subjects and setup sentinels to warn use after free errors
this._getValue$().complete();
this._getValid$().complete();
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(this._valid$ as BehaviorSubject<boolean>) = createSentinelSubject(
this._displayName,
false
);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(this._value$ as BehaviorSubject<Value>) = createSentinelSubject(
this._displayName,
this.defaultValue
);
}
}
FieldModel.prototype[FIELD_ID] = true;
export { FieldModel };