Search code examples
javascriptvalidationvue.jsvee-validate

vue.js VeeValidate - custom validator correctly compiles errors but does not toggle error class


I've written a custom validator like this:

    created () {
        this.$validator.extend('validateCert', {
            getMessage: (field) => {
                return field + ' is not a valid certificate';
            },
            validate: (value) => {
                return value.startsWith('-----BEGIN CERTIFICATE-----') && value.endsWith('-----END CERTIFICATE-----');
            }
        });
    }

I've attached it to a text area inside a modal:

    <div class="pb-3 mr-4">
        <b-form-textarea 
            type="text"
            v-validate="'required|validateCert'"
            data-vv-validate-on="change"
            v-model.trim="signedCerts[index]"
            data-vv-scope="uploadCert"
            :name="'certificate_' + index"
            :class="[{'is-invalid': errors.has('certificate_' + index)}]"
            rows="15"/>
        <fr-validation-error :validatorErrors="errors" :fieldName="'certificate_' + index"></fr-validation-error>
    </div>

Then - on button click I do the following:

uploadCerts (event) {
    let idmInstance = this.getRequestService(),
        body = {
            fromCSR: true,
            certs: _.each(this.signedCerts, (cert) => { 
                JSON.stringify(cert); 
            })
    };

this.$validator.validateAll('uploadCert').then((valid) => {
    // Prevent modal from closing
    event.preventDefault();

    if (valid) { // some more logic

If I inspect the computed errors object, I will see my failed validation:

{
    "items": [
        {
            "id": "19",
            "field": "certificate_0",
            "msg": "certificate_0 is not a valid certificate",
            "rule": "validateCert",
            "scope": "uploadCert",
            "regenerate": {
                "_custom": {
                    "type": "function",
                    "display": "<span>ƒ</span> regenerate()"
                }
            }
        }
    ]
}

and the value of 'valid' (either true or false) is accurate at all times. I'm just not seeing my error classes being triggered.


Solution

  • Hard to completely answer the question because part of it depends on what happens in fr-validation-error, but I think the problem is how you're using scopes.

    When you define data-vv-scope="uploadCert" that means that every reference to field-name has to be prefaced by uploadCert. in errors. So when you specify in your :class that errors.has('certificates_'+index), you have to change that to errors.has('uploadCert.certificates_'+index).

    Here's how it would look in full (minus the bootstrap-vue and multiple fields bits):

        <textarea
          v-validate="'required|validateCert'"
          data-vv-validate-on="change"
          data-vv-scope="uploadCert"
          v-model.trim="signedCert"
          name="certificate"
          class="form-control"
          :class="{ 'is-invalid': errors.has('uploadCert.certificate') }"
          rows="10"
        >
        </textarea>
    

    Full working example for one certificate upload field: https://codesandbox.io/s/z2owy0r2z3