UNPKG

@egova/components

Version:

components

306 lines (262 loc) 8.75 kB
import { Component, component, config, mixins, watch, inject } from "@egova/flagwind-web"; import AsyncValidator from "async-validator"; import "./index.scss"; @component({}) 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]] }; } @component({ name: "FormItem", template: require("./index.html") }) export default class FormItemComponent extends mixins(Emitter) { @inject() public formInstance: any; @config({ type: String, default: "" }) public label!: string; @config({ type: Number }) public labelWidth?: number; @config({ type: String }) public prop?: string; @config({ type: Boolean, default: false }) public required!: boolean; @config({ type: [Object, Array] }) public rules?: Object | Array<any>; @config({ type: String }) public error?: string; @config({ type: Boolean }) public validateStatus?: boolean; @config({ type: Boolean, default: true }) public showMessage!: boolean; @config({ type: String }) 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 = {}; @watch("error", { immediate: true }) public handler(val: any) { this.validateMessage = val; this.validateState = val ? "error" : ""; } @watch("validateStatus", { immediate: true }) public onValidateStatusChange(val: any) { this.validateState = val; } @watch("rules") public onRulesChange() { this.setRules(); } @watch("required") 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); } }