123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- <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>
|