UNPKG

8.1 kBPlain TextView Raw
1<template>
2 <div class="el-form-item" :class="[{
3 'el-form-item--feedback': elForm && elForm.statusIcon,
4 'is-error': validateState === 'error',
5 'is-validating': validateState === 'validating',
6 'is-success': validateState === 'success',
7 'is-required': isRequired || required
8 },
9 sizeClass ? 'el-form-item--' + sizeClass : ''
10 ]">
11 <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
12 <slot name="label">{{label + form.labelSuffix}}</slot>
13 </label>
14 <div class="el-form-item__content" :style="contentStyle">
15 <slot></slot>
16 <transition name="el-zoom-in-top">
17 <slot
18 v-if="validateState === 'error' && showMessage && form.showMessage"
19 name="error"
20 :error="validateMessage">
21 <div
22 class="el-form-item__error"
23 :class="{
24 'el-form-item__error--inline': typeof inlineMessage === 'boolean'
25 ? inlineMessage
26 : (elForm && elForm.inlineMessage || false)
27 }"
28 >
29 {{validateMessage}}
30 </div>
31 </slot>
32 </transition>
33 </div>
34 </div>
35</template>
36<script>
37 import AsyncValidator from 'async-validator';
38 import emitter from 'element-ui/src/mixins/emitter';
39 import objectAssign from 'element-ui/src/utils/merge';
40 import { noop, getPropByPath } from 'element-ui/src/utils/util';
41
42 export default {
43 name: 'ElFormItem',
44
45 componentName: 'ElFormItem',
46
47 mixins: [emitter],
48
49 provide() {
50 return {
51 elFormItem: this
52 };
53 },
54
55 inject: ['elForm'],
56
57 props: {
58 label: String,
59 labelWidth: String,
60 prop: String,
61 required: {
62 type: Boolean,
63 default: undefined
64 },
65 rules: [Object, Array],
66 error: String,
67 validateStatus: String,
68 for: String,
69 inlineMessage: {
70 type: [String, Boolean],
71 default: ''
72 },
73 showMessage: {
74 type: Boolean,
75 default: true
76 },
77 size: String
78 },
79 watch: {
80 error: {
81 immediate: true,
82 handler(value) {
83 this.validateMessage = value;
84 this.validateState = value ? 'error' : '';
85 }
86 },
87 validateStatus(value) {
88 this.validateState = value;
89 }
90 },
91 computed: {
92 labelFor() {
93 return this.for || this.prop;
94 },
95 labelStyle() {
96 const ret = {};
97 if (this.form.labelPosition === 'top') return ret;
98 const labelWidth = this.labelWidth || this.form.labelWidth;
99 if (labelWidth) {
100 ret.width = labelWidth;
101 }
102 return ret;
103 },
104 contentStyle() {
105 const ret = {};
106 const label = this.label;
107 if (this.form.labelPosition === 'top' || this.form.inline) return ret;
108 if (!label && !this.labelWidth && this.isNested) return ret;
109 const labelWidth = this.labelWidth || this.form.labelWidth;
110 if (labelWidth) {
111 ret.marginLeft = labelWidth;
112 }
113 return ret;
114 },
115 form() {
116 let parent = this.$parent;
117 let parentName = parent.$options.componentName;
118 while (parentName !== 'ElForm') {
119 if (parentName === 'ElFormItem') {
120 this.isNested = true;
121 }
122 parent = parent.$parent;
123 parentName = parent.$options.componentName;
124 }
125 return parent;
126 },
127 fieldValue() {
128 const model = this.form.model;
129 if (!model || !this.prop) { return; }
130
131 let path = this.prop;
132 if (path.indexOf(':') !== -1) {
133 path = path.replace(/:/, '.');
134 }
135
136 return getPropByPath(model, path, true).v;
137 },
138 isRequired() {
139 let rules = this.getRules();
140 let isRequired = false;
141
142 if (rules && rules.length) {
143 rules.every(rule => {
144 if (rule.required) {
145 isRequired = true;
146 return false;
147 }
148 return true;
149 });
150 }
151 return isRequired;
152 },
153 _formSize() {
154 return this.elForm.size;
155 },
156 elFormItemSize() {
157 return this.size || this._formSize;
158 },
159 sizeClass() {
160 return this.elFormItemSize || (this.$ELEMENT || {}).size;
161 }
162 },
163 data() {
164 return {
165 validateState: '',
166 validateMessage: '',
167 validateDisabled: false,
168 validator: {},
169 isNested: false
170 };
171 },
172 methods: {
173 validate(trigger, callback = noop) {
174 this.validateDisabled = false;
175 const rules = this.getFilteredRule(trigger);
176 if ((!rules || rules.length === 0) && this.required === undefined) {
177 callback();
178 return true;
179 }
180
181 this.validateState = 'validating';
182
183 const descriptor = {};
184 if (rules && rules.length > 0) {
185 rules.forEach(rule => {
186 delete rule.trigger;
187 });
188 }
189 descriptor[this.prop] = rules;
190
191 const validator = new AsyncValidator(descriptor);
192 const model = {};
193
194 model[this.prop] = this.fieldValue;
195
196 validator.validate(model, { firstFields: true }, (errors, invalidFields) => {
197 this.validateState = !errors ? 'success' : 'error';
198 this.validateMessage = errors ? errors[0].message : '';
199
200 callback(this.validateMessage, invalidFields);
201 this.elForm && this.elForm.$emit('validate', this.prop, !errors);
202 });
203 },
204 clearValidate() {
205 this.validateState = '';
206 this.validateMessage = '';
207 this.validateDisabled = false;
208 },
209 resetField() {
210 this.validateState = '';
211 this.validateMessage = '';
212
213 let model = this.form.model;
214 let value = this.fieldValue;
215 let path = this.prop;
216 if (path.indexOf(':') !== -1) {
217 path = path.replace(/:/, '.');
218 }
219
220 let prop = getPropByPath(model, path, true);
221
222 this.validateDisabled = true;
223 if (Array.isArray(value)) {
224 prop.o[prop.k] = [].concat(this.initialValue);
225 } else {
226 prop.o[prop.k] = this.initialValue;
227 }
228
229 this.broadcast('ElTimeSelect', 'fieldReset', this.initialValue);
230 },
231 getRules() {
232 let formRules = this.form.rules;
233 const selfRules = this.rules;
234 const requiredRule = this.required !== undefined ? { required: !!this.required } : [];
235
236 const prop = getPropByPath(formRules, this.prop || '');
237 formRules = formRules ? (prop.o[this.prop || ''] || prop.v) : [];
238
239 return [].concat(selfRules || formRules || []).concat(requiredRule);
240 },
241 getFilteredRule(trigger) {
242 const rules = this.getRules();
243
244 return rules.filter(rule => {
245 if (!rule.trigger || trigger === '') return true;
246 if (Array.isArray(rule.trigger)) {
247 return rule.trigger.indexOf(trigger) > -1;
248 } else {
249 return rule.trigger === trigger;
250 }
251 }).map(rule => objectAssign({}, rule));
252 },
253 onFieldBlur() {
254 this.validate('blur');
255 },
256 onFieldChange() {
257 if (this.validateDisabled) {
258 this.validateDisabled = false;
259 return;
260 }
261
262 this.validate('change');
263 }
264 },
265 mounted() {
266 if (this.prop) {
267 this.dispatch('ElForm', 'el.form.addField', [this]);
268
269 let initialValue = this.fieldValue;
270 if (Array.isArray(initialValue)) {
271 initialValue = [].concat(initialValue);
272 }
273 Object.defineProperty(this, 'initialValue', {
274 value: initialValue
275 });
276
277 let rules = this.getRules();
278
279 if (rules.length || this.required !== undefined) {
280 this.$on('el.form.blur', this.onFieldBlur);
281 this.$on('el.form.change', this.onFieldChange);
282 }
283 }
284 },
285 beforeDestroy() {
286 this.dispatch('ElForm', 'el.form.removeField', [this]);
287 }
288 };
289</script>