| <template> | 
|   <div class="el-form-item" :class="[{ | 
|       'el-form-item--feedback': elForm && elForm.statusIcon, | 
|       'is-error': validateState === 'error', | 
|       'is-validating': validateState === 'validating', | 
|       'is-success': validateState === 'success', | 
|       'is-required': isRequired || required, | 
|       'is-no-asterisk': elForm && elForm.hideRequiredAsterisk | 
|     }, | 
|     sizeClass ? 'el-form-item--' + sizeClass : '' | 
|   ]"> | 
|     <label-wrap | 
|       :is-auto-width="labelStyle && labelStyle.width === 'auto'" | 
|       :update-all="form.labelWidth === 'auto'"> | 
|       <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label"> | 
|         <slot name="label">{{label + form.labelSuffix}}</slot> | 
|       </label> | 
|     </label-wrap> | 
|     <div class="el-form-item__content" :style="contentStyle"> | 
|       <slot></slot> | 
|       <transition name="el-zoom-in-top"> | 
|         <slot | 
|           v-if="validateState === 'error' && showMessage && form.showMessage" | 
|           name="error" | 
|           :error="validateMessage"> | 
|           <div | 
|             class="el-form-item__error" | 
|             :class="{ | 
|               'el-form-item__error--inline': typeof inlineMessage === 'boolean' | 
|                 ? inlineMessage | 
|                 : (elForm && elForm.inlineMessage || false) | 
|             }" | 
|           > | 
|             {{validateMessage}} | 
|           </div> | 
|         </slot> | 
|       </transition> | 
|     </div> | 
|   </div> | 
| </template> | 
| <script> | 
|   import AsyncValidator from 'async-validator'; | 
|   import emitter from 'element-ui/src/mixins/emitter'; | 
|   import objectAssign from 'element-ui/src/utils/merge'; | 
|   import { noop, getPropByPath } from 'element-ui/src/utils/util'; | 
|   import LabelWrap from './label-wrap'; | 
|   export default { | 
|     name: 'ElFormItem', | 
|   | 
|     componentName: 'ElFormItem', | 
|   | 
|     mixins: [emitter], | 
|   | 
|     provide() { | 
|       return { | 
|         elFormItem: this | 
|       }; | 
|     }, | 
|   | 
|     inject: ['elForm'], | 
|   | 
|     props: { | 
|       label: String, | 
|       labelWidth: String, | 
|       prop: String, | 
|       required: { | 
|         type: Boolean, | 
|         default: undefined | 
|       }, | 
|       rules: [Object, Array], | 
|       error: String, | 
|       validateStatus: String, | 
|       for: String, | 
|       inlineMessage: { | 
|         type: [String, Boolean], | 
|         default: '' | 
|       }, | 
|       showMessage: { | 
|         type: Boolean, | 
|         default: true | 
|       }, | 
|       size: String | 
|     }, | 
|     components: { | 
|       // use this component to calculate auto width | 
|       LabelWrap | 
|     }, | 
|     watch: { | 
|       error: { | 
|         immediate: true, | 
|         handler(value) { | 
|           this.validateMessage = value; | 
|           this.validateState = value ? 'error' : ''; | 
|         } | 
|       }, | 
|       validateStatus(value) { | 
|         this.validateState = value; | 
|       }, | 
|       rules(value) { | 
|         if ((!value || value.length === 0) && this.required === undefined) { | 
|           this.clearValidate(); | 
|         } | 
|       } | 
|     }, | 
|     computed: { | 
|       labelFor() { | 
|         return this.for || this.prop; | 
|       }, | 
|       labelStyle() { | 
|         const ret = {}; | 
|         if (this.form.labelPosition === 'top') return ret; | 
|         const labelWidth = this.labelWidth || this.form.labelWidth; | 
|         if (labelWidth) { | 
|           ret.width = labelWidth; | 
|         } | 
|         return ret; | 
|       }, | 
|       contentStyle() { | 
|         const ret = {}; | 
|         const label = this.label; | 
|         if (this.form.labelPosition === 'top' || this.form.inline) return ret; | 
|         if (!label && !this.labelWidth && this.isNested) return ret; | 
|         const labelWidth = this.labelWidth || this.form.labelWidth; | 
|         if (labelWidth === 'auto') { | 
|           if (this.labelWidth === 'auto') { | 
|             ret.marginLeft = this.computedLabelWidth; | 
|           } else if (this.form.labelWidth === 'auto') { | 
|             ret.marginLeft = this.elForm.autoLabelWidth; | 
|           } | 
|         } else { | 
|           ret.marginLeft = labelWidth; | 
|         } | 
|         return ret; | 
|       }, | 
|       form() { | 
|         let parent = this.$parent; | 
|         let parentName = parent.$options.componentName; | 
|         while (parentName !== 'ElForm') { | 
|           if (parentName === 'ElFormItem') { | 
|             this.isNested = true; | 
|           } | 
|           parent = parent.$parent; | 
|           parentName = parent.$options.componentName; | 
|         } | 
|         return parent; | 
|       }, | 
|       fieldValue() { | 
|         const model = this.form.model; | 
|         if (!model || !this.prop) { return; } | 
|   | 
|         let path = this.prop; | 
|         if (path.indexOf(':') !== -1) { | 
|           path = path.replace(/:/, '.'); | 
|         } | 
|   | 
|         return getPropByPath(model, path, true).v; | 
|       }, | 
|       isRequired() { | 
|         let rules = this.getRules(); | 
|         let isRequired = false; | 
|   | 
|         if (rules && rules.length) { | 
|           rules.every(rule => { | 
|             if (rule.required) { | 
|               isRequired = true; | 
|               return false; | 
|             } | 
|             return true; | 
|           }); | 
|         } | 
|         return isRequired; | 
|       }, | 
|       _formSize() { | 
|         return this.elForm.size; | 
|       }, | 
|       elFormItemSize() { | 
|         return this.size || this._formSize; | 
|       }, | 
|       sizeClass() { | 
|         return this.elFormItemSize || (this.$ELEMENT || {}).size; | 
|       } | 
|     }, | 
|     data() { | 
|       return { | 
|         validateState: '', | 
|         validateMessage: '', | 
|         validateDisabled: false, | 
|         validator: {}, | 
|         isNested: false, | 
|         computedLabelWidth: '' | 
|       }; | 
|     }, | 
|     methods: { | 
|       validate(trigger, callback = noop) { | 
|         this.validateDisabled = false; | 
|         const rules = this.getFilteredRule(trigger); | 
|         if ((!rules || rules.length === 0) && this.required === undefined) { | 
|           callback(); | 
|           return true; | 
|         } | 
|   | 
|         this.validateState = 'validating'; | 
|   | 
|         const descriptor = {}; | 
|         if (rules && rules.length > 0) { | 
|           rules.forEach(rule => { | 
|             delete rule.trigger; | 
|           }); | 
|         } | 
|         descriptor[this.prop] = rules; | 
|   | 
|         const validator = new AsyncValidator(descriptor); | 
|         const model = {}; | 
|   | 
|         model[this.prop] = this.fieldValue; | 
|   | 
|         validator.validate(model, { firstFields: true }, (errors, invalidFields) => { | 
|           this.validateState = !errors ? 'success' : 'error'; | 
|           this.validateMessage = errors ? errors[0].message : ''; | 
|   | 
|           callback(this.validateMessage, invalidFields); | 
|           this.elForm && this.elForm.$emit('validate', this.prop, !errors, this.validateMessage || null); | 
|         }); | 
|       }, | 
|       clearValidate() { | 
|         this.validateState = ''; | 
|         this.validateMessage = ''; | 
|         this.validateDisabled = false; | 
|       }, | 
|       resetField() { | 
|         this.validateState = ''; | 
|         this.validateMessage = ''; | 
|   | 
|         let model = this.form.model; | 
|         let value = this.fieldValue; | 
|         let path = this.prop; | 
|         if (path.indexOf(':') !== -1) { | 
|           path = path.replace(/:/, '.'); | 
|         } | 
|   | 
|         let prop = getPropByPath(model, path, true); | 
|   | 
|         this.validateDisabled = true; | 
|         if (Array.isArray(value)) { | 
|           prop.o[prop.k] = [].concat(this.initialValue); | 
|         } else { | 
|           prop.o[prop.k] = this.initialValue; | 
|         } | 
|   | 
|         // reset validateDisabled after onFieldChange triggered | 
|         this.$nextTick(() => { | 
|           this.validateDisabled = false; | 
|         }); | 
|   | 
|         this.broadcast('ElTimeSelect', 'fieldReset', this.initialValue); | 
|       }, | 
|       getRules() { | 
|         let formRules = this.form.rules; | 
|         const selfRules = this.rules; | 
|         const requiredRule = this.required !== undefined ? { required: !!this.required } : []; | 
|   | 
|         const prop = getPropByPath(formRules, this.prop || ''); | 
|         formRules = formRules ? (prop.o[this.prop || ''] || prop.v) : []; | 
|   | 
|         return [].concat(selfRules || formRules || []).concat(requiredRule); | 
|       }, | 
|       getFilteredRule(trigger) { | 
|         const rules = this.getRules(); | 
|   | 
|         return rules.filter(rule => { | 
|           if (!rule.trigger || trigger === '') return true; | 
|           if (Array.isArray(rule.trigger)) { | 
|             return rule.trigger.indexOf(trigger) > -1; | 
|           } else { | 
|             return rule.trigger === trigger; | 
|           } | 
|         }).map(rule => objectAssign({}, rule)); | 
|       }, | 
|       onFieldBlur() { | 
|         this.validate('blur'); | 
|       }, | 
|       onFieldChange() { | 
|         if (this.validateDisabled) { | 
|           this.validateDisabled = false; | 
|           return; | 
|         } | 
|   | 
|         this.validate('change'); | 
|       }, | 
|       updateComputedLabelWidth(width) { | 
|         this.computedLabelWidth = width ? `${width}px` : ''; | 
|       }, | 
|       addValidateEvents() { | 
|         const rules = this.getRules(); | 
|   | 
|         if (rules.length || this.required !== undefined) { | 
|           this.$on('el.form.blur', this.onFieldBlur); | 
|           this.$on('el.form.change', this.onFieldChange); | 
|         } | 
|       }, | 
|       removeValidateEvents() { | 
|         this.$off(); | 
|       } | 
|     }, | 
|     mounted() { | 
|       if (this.prop) { | 
|         this.dispatch('ElForm', 'el.form.addField', [this]); | 
|   | 
|         let initialValue = this.fieldValue; | 
|         if (Array.isArray(initialValue)) { | 
|           initialValue = [].concat(initialValue); | 
|         } | 
|         Object.defineProperty(this, 'initialValue', { | 
|           value: initialValue | 
|         }); | 
|   | 
|         this.addValidateEvents(); | 
|       } | 
|     }, | 
|     beforeDestroy() { | 
|       this.dispatch('ElForm', 'el.form.removeField', [this]); | 
|     } | 
|   }; | 
| </script> |