ohayolibs
Version:
Ohayo is a set of essential modules for ohayojp.
114 lines (100 loc) • 3.52 kB
text/typescript
import { OhayoSFConfig } from '@ohayo/util';
import { SF_SEQ } from '../const';
import { SFValue } from '../interface';
import { SFSchema } from '../schema/index';
import { SFUISchema, SFUISchemaItem } from '../schema/ui';
import { SchemaValidatorFactory } from '../validator.factory';
import { FormProperty, PropertyGroup } from './form.property';
import { FormPropertyFactory } from './form.property.factory';
import { ObjectProperty } from './object.property';
export class ArrayProperty extends PropertyGroup {
constructor(
private formPropertyFactory: FormPropertyFactory,
schemaValidatorFactory: SchemaValidatorFactory,
schema: SFSchema,
ui: SFUISchema | SFUISchemaItem,
formData: {},
parent: PropertyGroup | null,
path: string,
options: OhayoSFConfig,
) {
super(schemaValidatorFactory, schema, ui, formData, parent, path, options);
this.properties = [];
}
getProperty(path: string): FormProperty | undefined {
const subPathIdx = path.indexOf(SF_SEQ);
const pos = +(subPathIdx !== -1 ? path.substr(0, subPathIdx) : path);
const list = this.properties as PropertyGroup[];
if (isNaN(pos) || pos >= list.length) {
return undefined;
}
const subPath = path.substr(subPathIdx + 1);
return list[pos].getProperty(subPath);
}
setValue(value: SFValue, onlySelf: boolean): void {
this.properties = [];
this.clearErrors();
this.resetProperties(value);
this.updateValueAndValidity({ onlySelf, emitValueEvent: true });
}
resetValue(value: SFValue, onlySelf: boolean): void {
this._value = value || this.schema.default || [];
this.setValue(this._value, onlySelf);
}
_hasValue(): boolean {
return true;
}
_updateValue(): void {
const value: any[] = [];
this.forEachChild((property: FormProperty) => {
if (property.visible && property._hasValue()) {
value.push({ ...(this.widget?.cleanValue ? null : property.formData), ...property.value });
}
});
this._value = value;
}
private addProperty(formData: {}): FormProperty {
const newProperty = this.formPropertyFactory.createProperty(
this.schema.items!,
this.ui.$items,
formData,
this as PropertyGroup,
) as ObjectProperty;
(this.properties as FormProperty[]).push(newProperty);
return newProperty;
}
private resetProperties(formDatas: Array<{}>): void {
for (const item of formDatas) {
const property = this.addProperty(item);
property.resetValue(item, true);
}
}
private clearErrors(property?: FormProperty): void {
(property || this)._objErrors = {};
}
// #region actions
add(formData: {}): FormProperty {
const newProperty = this.addProperty(formData);
newProperty.resetValue(formData, false);
return newProperty;
}
remove(index: number): void {
const list = this.properties as FormProperty[];
this.clearErrors();
list.splice(index, 1);
list.forEach((property, idx) => {
property.path = [property.parent!.path, idx].join(SF_SEQ);
this.clearErrors(property);
// TODO: 受限于 sf 的设计思路,对于移除数组项需要重新对每个子项进行校验,防止错误被父级合并后引起始终是错误的现象
if (property instanceof ObjectProperty) {
property.forEachChild(p => {
p.updateValueAndValidity();
});
}
});
if (list.length === 0) {
this.updateValueAndValidity();
}
}
// #endregion
}