I have a parent component rendering a personal details component and am injecting the parent's validator scope. if I use the v-validate directive and this.$validator.validateAll() or this.$validator.validate('field_name') this works fine.
However, I need to validate some fields independently, but when using this.$validator.attach('first_name', 'required') for example I am getting the following warning [vee-validate] A field is missing a "name" or "data-vv-name" attribute. I have tried moving the call to attach the validators into the click handler, in case the input element isn't fully rendered when calling it from mounted() but still get the same problem. I have also tried both name or data-vv-name attributes independently.
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 = '';
}
I think you might be thinking about it wrong. Ideally the validation logic should be within the child component, not the parent. But you should still be able to use the parent to run the validations. As you are injecting the validator instance from the parent, you should be able to update your child component to the following:
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');
}
}
Then you can remove the attachValidators method from the parent. This should attach those validation rules to the validator instance being provided by the parent. So in theory the parent can run this.$validator.validateAll(); and it should validate based on the rules within the child component.
I've managed to achieve what I needed - validation of particular fields - by using the data-vv-validate-on attribute along with a custom event. This way I can fire an event on whichever inputs need validating when the button is clicked.
Parent component updated to:
@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();
}
}
And PersonalDetails component:
@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'));
}
}
I still don't understand why the attach method was not working, but this alternative does work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With