Search code examples
vue.jsvuelidate

Bootstrap-Vue + Vuelidate: "Dialog" for creating and updating data


I'm trying to reuse the dialog form but when trying to update Vuelidate says the form is invalid, I'm not sure why. This is my code.

<b-modal size="lg" ref="my-modal" hide-footer :title="modalTitle + ' User'">
    <form @submit.prevent="onSubmit" @reset.prevent="onReset">
        <b-row>
            <b-col>
                <b-form-input id="input-name"
                              v-model="form.name"
                              @input="$v.form.name.$touch()"
                              :state="$v.form.name.$dirty ? !$v.form.name.$error : null"
                              placeholder="Name"
                              trim></b-form-input>
             </b-col>
             <b-col>
                <b-form-input id="input-email"
                              v-model="form.email"
                              @input="$v.form.email.$touch()"
                              :state="$v.form.email.$dirty ? !$v.form.email.$error : null"
                              placeholder="Email"
                              trim></b-form-input>
            </b-col>
        </b-row>

        <b-row v-if="mode === 0">
            <b-col>
                <b-form-input id="input-password"
                              v-model="form.password"
                              @input="$v.form.password.$touch()"
                              :state="$v.form.password.$dirty ? !$v.form.password.$error : null"
                              type="password"
                              placeholder="Password"
                              trim></b-form-input>
            </b-col>
            <b-col>
                <b-form-input id="input-password-confirm"
                               v-model="form.password_confirmation"
                               @input="$v.form.password_confirmation.$touch()"
                               :state="$v.form.password_confirmation.$dirty ? !$v.form.password_confirmation.$error : null"
                               type="password"
                               placeholder="Password Confirmation"
                               trim></b-form-input>
            </b-col>
        </b-row>

        <b-button v-if="mode === 1"
                  class="mb-1"
                  :class="visible ? null : 'collapsed'"
                  :aria-expanded="visible ? 'true' : 'false'"
                  aria-controls="collapse-4"
                  @click="visible = !visible">Change Password
        </b-button>
        <b-collapse v-model="visible" class="mt-2">
            <b-form-input id="input-password-edit"
                          v-model="form.password_edit"
                          @input="$v.form.password_edit.$touch()"
                          :state="$v.form.password_edit.$dirty ? !$v.form.password_edit.$error : null"
                          type="password"
                          placeholder="New Password"
                          trim></b-form-input>
        </b-collapse>

        <b-row>
            <b-col>
                <b-form-select :options="roles"
                               v-model="form.role"
                               @input="$v.form.role.$touch()"
                               :state="$v.form.role.$dirty ? !$v.form.role.$error : null"
                               placeholder="User Role"></b-form-select>
            </b-col>
        </b-row>

        <b-row align-h="end" style="padding-left: 1rem; padding-right: 1rem">
            <b-button class="mr-1" @click="cancel" variant="secondary">Cancel</b-button>
            <b-button type="submit" variant="primary">Save</b-button>
        </b-row>
    </form>
</b-modal>
 data() {
        return {
            url: '/users',
            form: {
                name: '',
                email: '',
                password: '',
                password_confirmation: '',
                password_edit: '',
                role: ''
            },
            users: [],
            roles: [],
        }
    },
    validations: {
        form: {
            name: {
                required
            },
            email: {
                required,
                email
            },
            password: {
                required: requiredIf(this.modalTitle() === 'New')
            },
            password_confirmation: {
                required: requiredIf(this.modalTitle() === 'New'),
                sameAsPassword: sameAs('password')
            },
            role: {
                required
            },
            password_edit: {
                required: requiredIf(this.modalTitle() === 'Edit')
            }

        }
    },
 methods: {
        create() {
            this.onReset();
            this.mode = 0;
            this.$refs['my-modal'].show();
        },
        edit(item) {
            this.onReset();
            this.mode = 1;
            this.form = _.cloneDeep(item);
            this.form.role = this.form.roles[0]['id'];

            this.$refs['my-modal'].show();
        },
        onSubmit() {
            this.$v.$touch()
            console.log(this.$v.invalid);
            if (!this.$v.$invalid) {
                if (this.mode === 0) {
                    this.$inertia.post(this.url, {
                        name: this.form.name,
                        email: this.form.email,
                        password: this.form.password,
                        password_confirmation: this.form.password_confirmation,
                        role: this.form.role,
                    }).then(
                        () => {
                            if (Object.entries(this.$page.props.errors).length === 0) {
                                this.$refs['my-modal'].hide();
                                this.onReset();

                                this.$bvToast.toast('New User Created', {
                                    title: 'Action Successful',
                                    variant: 'success',
                                    toaster: 'b-toaster-top-center',
                                    solid: true
                                });
                            }
                        }
                    )
                } else {
                    console.log('here')
                    this.$inertia.put(this.url + '/' + this.form.id, {
                        name: this.form.name,
                        email: this.form.email,
                        role: this.form.role,
                        password_edit: this.form.password_edit
                    }).then(
                        () => {
                            if (Object.entries(this.$page.props.errors).length === 0) {
                                this.$refs['my-modal'].hide();
                                this.onReset();

                                this.$bvToast.toast('User Updated', {
                                    title: 'Action Successful',
                                    variant: 'success',
                                    toaster: 'b-toaster-top-center',
                                    solid: true
                                });
                            }
                        }
                    )
                }
            }
        },
    },

In the onSubmit() if I add a console.log it stops working after if (!this.$v.$invalid) which means that I'm not using Vuelidate correctly but in the validations when I try to use requiredIf I get an error

Error in created hook: "TypeError: Cannot read property 'modalTitle' of undefined"

TypeError: Cannot read property 'modalTitle' of undefined

this.modelTitle() is a computed property, I also tried doing required: requiredIf(this.mode === 1) but I get the same errors.

How can I fix it so that when creating the required fields include the password and password_confimation but when editing don't require them?


Solution

  • The solution is to change the validators like this, in my case to be able to edit a password a section opens up using the variable visible so only when that section is visible it will require the new password, if the section is not visible then the password doesn't require being changed.

        validations: {
            form: {
                password: {
                    required: requiredIf(function (pass) {
                        return !this.form.id
                    }),
                },
                password_confirmation: {
                    required: requiredIf(function (pass) {
                        return !this.form.id
                    }),
                    sameAsPassword: sameAs('password')
                },
                password_edit: {
                    required: requiredIf(function (pass) {
                        return this.form.id && this.visible
                    }),
                }
            }
        },