@egova/components
Version:
components
306 lines (262 loc) • 8.75 kB
text/typescript
import {
Component,
component,
config,
mixins,
watch,
inject
} from "@egova/flagwind-web";
import AsyncValidator from "async-validator";
import "./index.scss";
export class Emitter extends Component {
public dispatch(componentName: any, eventName: any, params: any) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params) as any);
}
}
public broadcast(componentName: any, eventName: any, params: any) {
this.$children.forEach((child: any) => {
const name = child.$options.name;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat(params));
} else {
// todo 如果 params 是空数组,接收到的会是 undefined
this.broadcast.apply(
child,
[componentName, eventName].concat([params]) as any
);
}
});
}
}
export function getPropByPath(obj: any, path: any) {
let tempObj = obj;
path = path.replace(/\[(\w+)\]/g, ".$1");
path = path.replace(/^\./, "");
let keyArr = path.split(".");
let i = 0;
for (let len = keyArr.length; i < len - 1; ++i) {
let key = keyArr[i];
if (key in tempObj) {
tempObj = tempObj[key];
} else {
throw new Error(
"[iView warn]: please transfer a valid prop path to form item!"
);
}
}
return {
o: tempObj,
k: keyArr[i],
v: tempObj[keyArr[i]]
};
}
export default class FormItemComponent extends mixins(Emitter) {
public formInstance: any;
public label!: string;
public labelWidth?: number;
public prop?: string;
public required!: boolean;
public rules?: Object | Array<any>;
public error?: string;
public validateStatus?: boolean;
public showMessage!: boolean;
public labelFor?: string;
public prefixCls: string = "ivu-form-item";
public isRequired = false;
public validateState: string = "";
public validateMessage: string = "";
public validateDisabled: boolean = false;
public validator: any = {};
public handler(val: any) {
this.validateMessage = val;
this.validateState = val ? "error" : "";
}
public onValidateStatusChange(val: any) {
this.validateState = val;
}
public onRulesChange() {
this.setRules();
}
public onrequiredChange(n: any, o: any) {
this.isRequired = n;
if (o && !n) {
this.resetField();
}
}
public get classes() {
return [
`${this.prefixCls}`,
{
[`${this.prefixCls}-required`]:
this.required || this.isRequired,
[`${this.prefixCls}-error`]: this.validateState === "error",
[`${this.prefixCls}-validating`]:
this.validateState === "validating"
}
];
}
public get fieldValue() {
const model = this.formInstance.model;
if (!model || !this.prop) {
return;
}
let path = this.prop;
if (path.indexOf(":") !== -1) {
path = path.replace(/:/, ".");
}
return getPropByPath(model, path).v;
}
public get labelStyles() {
let style: any = {};
const labelWidth =
this.labelWidth === 0 || this.labelWidth
? this.labelWidth
: this.formInstance.labelWidth;
if (labelWidth || labelWidth === 0) {
style.width = `${labelWidth}px`;
}
return style;
}
public get contentStyles() {
let style: any = {};
const labelWidth =
this.labelWidth === 0 || this.labelWidth
? this.labelWidth
: this.formInstance.labelWidth;
if (labelWidth || labelWidth === 0) {
style.marginLeft = `${labelWidth}px`;
}
return style;
}
public setRules() {
let rules = this.getRules();
if (rules.length && this.required) {
return;
} else if (rules.length) {
rules.every((rule: any) => {
this.isRequired = rule.required;
});
} else if (this.required) {
this.isRequired = this.required;
}
this.$off("on-form-blur", this.onFieldBlur);
this.$off("on-form-change", this.onFieldChange);
this.$on("on-form-blur", this.onFieldBlur);
this.$on("on-form-change", this.onFieldChange);
}
public getRules() {
let formRules = this.formInstance.rules;
const selfRules = this.rules;
formRules = formRules ? formRules[this.prop as any] : [];
return [].concat(selfRules || formRules || []);
}
public getFilteredRule(trigger: any) {
const rules: any = this.getRules();
return rules.filter(
(rule: any) => !rule.trigger || rule.trigger.indexOf(trigger) !== -1
);
}
public validate(
trigger: any,
callback: any = () => {
console.warn("form-item: callback is empty");
}
) {
let rules: any = this.getFilteredRule(trigger);
if (!rules || rules.length === 0) {
if (!this.required) {
callback();
return true;
} else {
rules = [{ required: true }];
}
}
this.validateState = "validating";
let descriptor: any = {};
descriptor[this.prop as string] = rules;
const validator = new AsyncValidator(descriptor);
let model: any = {};
model[this.prop as any] = this.fieldValue;
validator.validate(model, { firstFields: true }, errors => {
this.validateState = !errors ? "success" : "error";
this.validateMessage = errors ? errors[0].message : "";
callback(this.validateMessage);
this.formInstance &&
this.formInstance.$emit(
"on-validate",
this.prop,
!errors,
this.validateMessage || null
);
});
this.validateDisabled = false;
}
public resetField() {
this.validateState = "";
this.validateMessage = "";
let model = this.formInstance.model;
let value = this.fieldValue;
let path: any = this.prop;
if (path.indexOf(":") !== -1) {
path = path.replace(/:/, ".");
}
let prop = getPropByPath(model, path);
if (Array.isArray(value)) {
this.validateDisabled = true;
prop.o[prop.k] = [].concat((<any>this).initialValue);
} else {
this.validateDisabled = true;
prop.o[prop.k] = (<any>this).initialValue;
}
}
public onFieldBlur() {
this.validate("blur");
}
public onFieldChange() {
if (this.validateDisabled) {
this.validateDisabled = false;
return;
}
this.validate("change");
}
public mounted() {
if (this.prop) {
this.dispatch("iForm", "on-form-item-add", this);
Object.defineProperty(this, "initialValue", {
value: this.fieldValue
});
this.setRules();
}
}
public beforeDestroy() {
this.dispatch("iForm", "on-form-item-remove", this);
}
}