0

Using element-ui, the form validation is pretty decent, so I was expecting it to be pretty straight-forward to "wire up" a variable that represents whether the form is valid to the "submit" button.

I can certainly write a validation function and attach it to appropriate events on every field, but that seems duplicative.

For example, each rule already has a trigger that tells it when to evaluate the rule (e.g. blur, change). If I have to attach an event to each el-input that mirrors the same triggers, that feels fragile to me.

For example, these rules trigger on blur or change.

    rules: {
        username: [
            {
                required: true,
                message: "please enter user name",
                trigger: "blur"
            },
            {
                min: 3,
                max: 32,
                message: "length must be 3 to 32 characters",
                trigger: "blur"
            }
        ],
        password: [
            {
                required: true,
                message: "please enter password",
                trigger: "change"
            }
        ]
    }

Am I missing something? Is there a way to do this, uh, elegantly?

2
  • see github.com/vuejs/awesome-vue#validation Commented Jan 14, 2018 at 0:18
  • I was hoping for something that takes advantage of the built-in validation in element-ui form components, which is based on "async-validator". Commented Jan 14, 2018 at 1:23

2 Answers 2

2

Here's what I ended up doing:

I used the vue.js 'watch' facility to monitor the form data (the key being that 'deep' is set so it monitors the field values) and run a check on it, updating a variable that disables the submit button:

The data section contains my form model and the enable variable:

data() {
    return {
        loginForm: {
            username: "",
            password: ""
        },
        formValid: false,
        ...

Which is attached to the button:

<el-button @click="submit" type="primary" :disabled="!formValid">Log In</el-button>

And the validation code, which is very generic (and may be able to be moved to a plugin):

watch: {
  loginForm: {
    handler(){
      this.checkForm();
    },
    deep: true
  }
},
methods: {
    checkForm() {
        let fields = this.$refs.loginForm.fields;
        if (fields.find((f) => f.validateState === 'validating')) {
            setTimeout(() => {
                this.checkForm();
            }, 100);
        }
        this.$data.formValid = fields.every(f => {
            let valid = f.required && f.validateState === "success";
            let notErroring = !f.required && f.validateState !== "error";
            return valid || notErroring;
        }, true);
        console.log('valid:', this.$data.formValid);
    },
    ...

(got this last part from another very useful post. It craftily handles the possibility of in-flight validation)

Sign up to request clarification or add additional context in comments.

Comments

0

Updated answer for Element Plus [2023] with the Vue Composition API;

Add state for form validity using the form item's prop name (same name you use for the rules);

const formValidity = ref({
    oldPassword: false,
    newPassword: false,
    confirmPassword: false
});

Created a computed property which is based on these values;

const formValid = computed(() => {
    return (
        formValidity.value.oldPassword &&
        formValidity.value.newPassword &&
        formValidity.value.confirmPassword
    );
});

Create a handler for the form's @validate period (this event is fired each time validation occurs);

function validateHandler(propName, isValid) {
    formValidity.value[propName] = isValid;
}

Bind the handler with the "validate" event;

<el-form
    :model="ruleForm"
    :rules="rules"
    ref="ruleFormRef"
    @validate="validateHandler"
>

Disable the button based on the computed property;

<button
    :class="`${!formValid ? 'disabled' : ''}`"
    @click="submitForm()"
>
    Save
</button>

or

<button
    :disabled="!formValid"
    @click="submitForm()"
>
    Save
</button>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.