VeeValidate 附加方法:当字段有名称时,字段缺少 "name" 或 "data-vv-name" 属性

VeeValidate attach method: A field is missing a "name" or "data-vv-name" attribute when fields do have name

我有一个呈现个人详细信息组件的父组件,并且正在注入父组件的验证器范围。如果我使用 v-validate 指令和 this.$validator.validateAll()this.$validator.validate('field_name') 这工作正常。

但是,我需要独立验证一些字段,但是当使用 this.$validator.attach('first_name', 'required') 例如我收到以下警告 [vee-validate] A field is missing a "name" or "data-vv-name" attribute。我尝试将调用移动到点击处理程序中以附加验证器,以防输入元素在从 mounted() 调用时未完全呈现但仍然遇到相同的问题。我还分别尝试了 namedata-vv-name 属性。

Parent.ts

import { Vue, Component } from 'vue-property-decorator';

import PersonalDetailsComponent from './PersonalDetails';

@Component({
    template: `
        <div class="container">
            <personal-details-component></personal-details-component>

            <div class="row">
                    <Button :onClick="handleButtonClick" :buttonText="'Validate'"></Button>
            </div>
        </div>
    `,
    components: {
        PersonalDetailsComponent,
    },
    $_veeValidate: {validator: 'new'}
})
export default class ClaimComponent extends Vue {

    mounted() {
        this.attachValidators();
    }

    handleButtonClick() {
        this.$validator.validateAll();
    }

    attachValidators() {
        console.log(document.getElementsByName('first_name')); // Finds the element

        this.$validator.attach('first_name', 'required');
        this.$validator.attach('surname', 'required');
        this.$validator.attach('email', 'required');
    }

}

PersonalDetails.ts

import {Vue, Component, Inject} from 'vue-property-decorator';

import {Validator} from 'vee-validate';

@Component({
    template: `
    <div class="row">
        <div class="col-12">
            <form class="material-form">
                <div class="group w-third">
                    <input v-model="first_name" type="text" name="first_name" required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>First name</label>
                    <span class="form-text error-text">{{ errors.first('first_name') }}</span>
                </div>
                <div class="group w-third">
                    <input v-model="surname" type="text" name="surname" required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>Surname</label>
                    <span class="form-text error-text">{{ errors.first('surname') }}</span>
                </div>
                <div class="group w-third">
                    <input v-model="email" type="text" name="email" required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>Email address</label>
                    <span class="form-text error-text">{{ errors.first('email') }}</span>
                </div>
            </form>
        </div>
    </div>
    `
})
export default class PersonalDetailsComponent extends Vue {
    @Inject('$validator') public $validator!: Validator;

    first_name: string = '';
    surname: string = '';
    email: string = '';

}

我想你可能想错了。理想情况下,验证逻辑应该在子组件中,而不是在父组件中。但是您应该 仍然能够使用父级来运行 验证。当您从父级注入验证器实例时,您应该能够将您的子组件更新为以下内容:

export default class PersonalDetailsComponent extends Vue {
    @Inject('$validator') public $validator!: Validator;

    first_name: string = '';
    surname: string = '';
    email: string = '';

    public mounted() {
        this.$validator.attach('first_name', 'required');
        this.$validator.attach('surname', 'required');
        this.$validator.attach('email', 'required');
    }
}

然后您可以从父项中删除 attachValidators 方法。这应该将这些验证规则附加到父级提供的验证器实例。所以理论上父组件可以 运行 this.$validator.validateAll(); 并且它应该根据子组件中的规则进行验证。

通过使用 data-vv-validate-on 属性和自定义事件,我已经设法实现了我所需要的 - 特定字段的验证。这样我就可以在单击按钮时对需要验证的输入触发事件。

父组件更新为:

@Component({
    template: `
        <div class="container">
            <personal-details-component ref="personalDetails"></personal-details-component>

            <div class="row">
                    <Button :onClick="handleButtonClick" :buttonText="'Validate'"></Button>
            </div>
        </div>
    `,
    components: {
        PersonalDetailsComponent,
    },
    $_veeValidate: {validator: 'new'}
})
export default class ClaimComponent extends Vue {
    $refs!: {
        personalDetails: PersonalDetailsComponent
    }

    handleButtonClick() {
        this.$refs.personalDetails.validateInput();
    }
}

和 PersonalDetails 组件:

@Component({
    template: `
    <div class="row">
        <div class="col-12">
            <form class="material-form">
                <div class="group w-third">
                    <input v-model="first_name" ref="firstName" type="text" name="first_name"
                    v-validate="'required'" 
                    data-vv-validate-on="validateStep" required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>First name</label>
                    <span class="form-text error-text">{{ errors.first('first_name') }}</span>
                </div>
                <div class="group w-third">
                    <input v-model="surname" ref="surname" type="text" name="surname" 
                    v-validate="'required'"
                    data-vv-validate-on="validateStep" required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>Surname</label>
                    <span class="form-text error-text">{{ errors.first('surname') }}</span>
                </div>
                <div class="group w-third">
                    <input v-model="email" ref="email" type="text" name="email" 
                    data-vv-validate-on="validateStep" v-validate="'required|email'" 
                    required>
                    <span class="highlight"></span>
                    <span class="bar"></span>
                    <label>Email address</label>
                    <span class="form-text error-text">{{ errors.first('email') }}</span>
                </div>
            </form>
        </div>
    </div>
    `
})
export default class PersonalDetailsComponent extends Vue {
    @Inject('$validator') public $validator!: Validator;
    $refs!: {
        firstName: HTMLInputElement,
        surname: HTMLInputElement,
        email: HTMLInputElement
    }

    first_name: string = '';
    surname: string = '';
    email: string = '';

    public validateInput() {
        this.$refs.firstName.dispatchEvent(new Event('validateStep'));
        this.$refs.surname.dispatchEvent(new Event('validateStep'));
        this.$refs.email.dispatchEvent(new Event('validateStep'));
    }
}

我仍然不明白为什么 attach 方法不起作用,但这个替代方法确实有效。

在我的例子中,data-vv-name="someName" 不见了。当你有两个类似的控件时,例如 v-autocomplete 那么具有相同名称的字段将相互冲突,所以为了解决这个问题你可以使用 data-vv-name="someName"。 示例如下:

 <v-autocomplete
          v-model="id"
          :items="items"
          :label="$t('scheduling.fields.truck-id')"
          :placeholder="$t('common.words.none')"
          readonly
          :disabled="!canEdit"
          :append-icon="''">
 </v-autocomplete>`

 <v-autocomplete
          v-model="id2"
          :items="items2"
          :label="label2"
          :placeholder="$t('common.words.none')"
          readonly
          data-vv-name="someName"
          :disabled="!canEdit"
          :append-icon="''">
 </v-autocomplete>`

Reference