Vuetify: Form fields custom validation message

Created on 16 Mar 2017  路  8Comments  路  Source: vuetifyjs/vuetify

Hi, how can I use Laravel for validation?

<template>
    <div>
        <form>
            <v-card>
                <v-card-text>
                    <v-row>
                        <v-text-field
                                label="Nome"
                                v-model="data.name"
                                name="name"
                                id="name"
                                :rules="rules.name"
                        ></v-text-field>
                    </v-row>
                    <v-row>
                        <v-text-field
                                label="Descrizione"
                                v-model="data.description"
                                name="description"
                                id="description"
                                multi-line
                        ></v-text-field>
                    </v-row>
                    <v-row>
                        <v-checkbox
                                label="Attivo"
                                name="status"
                                id="status"
                                v-model="data.status"
                                input-value="1"
                                success
                        ></v-checkbox>
                    </v-row>
                </v-card-text>
                <v-card-row actions>
                    <v-btn flat @click.native="submit" :loading="loading" type="submit">Salva</v-btn>
                </v-card-row>
            </v-card>
        </form>
    </div>
</template>

<script>

    import swal from 'sweetalert'

    export default {
        data() {
            return {
                data: {
                    name: null,
                    description: null,
                    status: null
                },
                rules: {
                    name: []
                },
                loading: false
            }
        },

        methods: {
            submit() {
                this.loading = true;
                this.$http.post('api/categories')
                    .then(response => {
                        this.loading = false;
                        swal('', response.data.message, response.data.status);
                    }, error => {
                        this.loading = false;
                        let errorType = error.response.status;
                        if (errorType == 422) {
                            let self = this;
                            _.forEach(error.response.data, (v, i) => {
                                 self.rules[i] = [() => v[0]]
                            });
                        } else {
                            swal(errorType.toString(), response.data.message, response.data.status);
                        }
                    })
            }
        }
    }

</script>

Most helpful comment

@beggiatom try this way, but i have some issues on the reset the error-messages after start typing again

<template>
  <v-form v-model="valid" ref="form" lazy-validation>
    <v-card>
      <v-card-title class="headline">Login</v-card-title>
      <v-card-text>
        <v-text-field
          label="E-Mail or Mobile number"
          v-model="email"
          :rules="emailRules"
          :error-messages="messages.email"
          required
        ></v-text-field>
        <v-text-field
          label="Password"
          v-model="password"
          :rules="passwordRules"
          :error-messages="messages.password"
          required
        ></v-text-field>
      </v-card-text>
      <v-card-actions>
        <v-btn @click="submit" color="primary" :loading="loading" :disabled="loading" >
          Log in
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-form>
</template>

<script>
  export default {
    name: "login",
    data: () => ({
      valid: false,
      loading: false,
      password: '',
      email: '',
      messages: {
        email: [],
        password: [],
      }
    }),
    computed: {

      emailRules() {
        return [
          v => !!v || 'E-mail is required',
          v => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mail must be valid'
        ]
      },

      passwordRules() {
        return [
          v => !!v || 'Password is required',
          v => v.length > 6 || 'Password must be grater than 6 characters'
        ]
      },

    },
    methods: {
      submit() {

        if (this.valid && this.$refs.form.validate()) {

          this.loading = true;

          let data = {
            email: this.email,
            password: this.password
          };

          this.$axios.post('api/login', data).then((res) => {
            this.loading = false;
            console.log(res)
          }).catch((err) => {
            this.valid = false;
            this.loading = false;

            let errors = err.response.data.errors;

            if (errors) {
              for (let field in errors) {
                this.messages[field] = errors[field]
              }
            }

          })

        }

      }
    }
  }
</script>

<style scoped>

</style>

All 8 comments

Please direct help related questions to the Vuetify gitter.

Update.

This system work but I have to click on the field to see the error message. How can I do to make the error refresh? I have to use watch? Sorry for my broken English.

OK try on Gitter

Now I tried with Vue-Validate

<form @submit.prevent="validateForm">
            <v-row row>
                <v-col xs4>
                    <v-subheader>Name</v-subheader>
                </v-col>
                <v-col xs4>
                    <v-text-field
                            v-model="form.name"
                            name="name"
                            label="Name"
                            v-validate="'required'"
                            v-bind:rules="rules.name"
                            class="input-group--focused"
                            single-line
                    ></v-text-field>
                </v-col>
            </v-row>

            <v-row row>
                <v-col xs4>
                    <v-subheader>Email</v-subheader>
                </v-col>
                <v-col xs4>
                    <v-text-field
                            v-model="form.email"
                            name="email"
                            label="Email"
                            v-validate="'required|email'"
                            v-bind:rules="rules.email"
                            class="input-group--focused"
                            single-line
                    ></v-text-field>
                </v-col>
            </v-row>

            <v-btn type="submit">Submit</v-btn>

        </form>
--------------
<script>
    import _ from 'lodash';

    export default {
        data(){
            return {
                form: {
                    name: '',
                    email: ''
                },
                rules: {
                    name: [],
                    email: [],
                }
            }
        },
        watch: {
            errors: {
                handler: function (val, oldVal) {
                    console.log('watcher');
                    _.forEach(this.rules, (val, key) => {
                        this.rules[key] = [() => this.errors.has(key) ? this.errors.first(key) : true];
                    });
                },
                deep: true
            }
        },
        methods: {
            validateForm(){
                this.$validator.validateAll().then(() => {
                    console.log('data', this.form);
                }).catch((err) => {
                    console.log(err.reason);
                });
            }
        }
    }

</script>

Please advice, if it is in correct.

@beggiatom try this way, but i have some issues on the reset the error-messages after start typing again

<template>
  <v-form v-model="valid" ref="form" lazy-validation>
    <v-card>
      <v-card-title class="headline">Login</v-card-title>
      <v-card-text>
        <v-text-field
          label="E-Mail or Mobile number"
          v-model="email"
          :rules="emailRules"
          :error-messages="messages.email"
          required
        ></v-text-field>
        <v-text-field
          label="Password"
          v-model="password"
          :rules="passwordRules"
          :error-messages="messages.password"
          required
        ></v-text-field>
      </v-card-text>
      <v-card-actions>
        <v-btn @click="submit" color="primary" :loading="loading" :disabled="loading" >
          Log in
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-form>
</template>

<script>
  export default {
    name: "login",
    data: () => ({
      valid: false,
      loading: false,
      password: '',
      email: '',
      messages: {
        email: [],
        password: [],
      }
    }),
    computed: {

      emailRules() {
        return [
          v => !!v || 'E-mail is required',
          v => /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(v) || 'E-mail must be valid'
        ]
      },

      passwordRules() {
        return [
          v => !!v || 'Password is required',
          v => v.length > 6 || 'Password must be grater than 6 characters'
        ]
      },

    },
    methods: {
      submit() {

        if (this.valid && this.$refs.form.validate()) {

          this.loading = true;

          let data = {
            email: this.email,
            password: this.password
          };

          this.$axios.post('api/login', data).then((res) => {
            this.loading = false;
            console.log(res)
          }).catch((err) => {
            this.valid = false;
            this.loading = false;

            let errors = err.response.data.errors;

            if (errors) {
              for (let field in errors) {
                this.messages[field] = errors[field]
              }
            }

          })

        }

      }
    }
  }
</script>

<style scoped>

</style>

@Qanah did you resolve issue with cleaning up error message after typing again?

@zorar4ik if it can help you I use this system

// RegisterView.vue
<template>
  <v-layout align-center justify-center>
    <v-flex xs12 sm8 md4>
      <v-card class="elevation-1">
        <v-toolbar dark color="primary" card>
          <v-toolbar-title>Register</v-toolbar-title>
          <v-spacer></v-spacer>
        </v-toolbar>
        <v-card-text>
          <v-form>
            <v-text-field v-model="form.fields.username" :prepend-icon="form.attrs.username.icon" id="username" name="username" :label="form.attrs.username.label" :type="form.attrs.username.type" :error="form.errors.username.state" :error-messages="form.errors.username.label" autofocus></v-text-field>
            <v-text-field v-model="form.fields.email" :prepend-icon="form.attrs.email.icon" id="email" name="email" :label="form.attrs.email.label" :type="form.attrs.email.type" :error="form.errors.email.state" :error-messages="form.errors.email.label"></v-text-field>
            <v-text-field v-model="form.fields.password" :prepend-icon="form.attrs.password.icon" id="password" name="password" :label="form.attrs.password.label" :type="form.attrs.password.type" :error="form.errors.password.state" :error-messages="form.errors.password.label"></v-text-field>
            <v-text-field v-model="form.fields.confirm_password" :prepend-icon="form.attrs.confirm_password.icon" id="confirm_password" name="confirm_password" :label="form.attrs.confirm_password.label" :type="form.attrs.confirm_password.type" :error="form.errors.confirm_password.state" :error-messages="form.errors.confirm_password.label"></v-text-field>
          </v-form>
        </v-card-text>
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn color="primary" depressed @click="register()">Continue</v-btn>
        </v-card-actions>
      </v-card>
    </v-flex>
  </v-layout>
</template>

<script>
import { user } from 'store/server'
import { validateForm } from 'store/form'
export default {
  data: () => {
    return {
      form: {
        fields: {
          username: '',
          email: '',
          password: '',
          confirm_password: ''
        },
        errors: {
          username: {
            state: false,
            label: []
          },
          email: {
            state: false,
            label: []
          },
          password: {
            state: false,
            label: []
          },
          confirm_password: {
            state: false,
            label: []
          }
        },
        attrs: {
          username: {
            label: 'Username',
            icon: 'person',
            type: 'text'
          },
          email: {
            label: 'E-mail',
            icon: 'email',
            type: 'email'
          },
          password: {
            label: 'Password',
            icon: 'lock',
            type: 'password'
          },
          confirm_password: {
            label: 'Password confirm',
            icon: 'lock',
            type: 'password'
          }
        }
      }
    }
  },

  methods: {
    register() {
      validateForm.init(this.form.errors)
      user.register(this.form.fields).then(r => {
        console.log(r)
      }).catch(e => {
        if (e.status === 422) {
          validateForm.set(this.form.errors, e.data)
        }
      })
    }
  },

  // Not always necessary
  destroyed() {
    validateForm.reset({
      fields: this.form.fields,
      errors: this.form.errors
    })
  }
}
</script>
// store/form.js
import forIn from 'lodash/forIn'

const validateForm = {
    // Remove all errors
    init(obj) {
      forIn(obj, (v, i) => {
        obj[i] = {
          state: false,
          label: []
        }
      })
      return obj
    },
    // Set form errors
    set(obj, errors) {
      let ers = obj
      forIn(errors, (v, i) => {
        ers[i] = v
      })
      return ers
    },
    // Reset all fields and remove all errors
    reset(obj) {
      forIn(obj.fields, (f, i) => {
        obj.fields[i] = ''
      })
      forIn(obj.errors, (e, i) => {
        obj.errors[i] = {
          state: false,
          label: []
        }
      })
      return obj
    }
  }

  export {
      validateForm
  }
// store/server
import { host } from 'path/config'

const api = axios.create({ 
   baseURL: host
 })

api.interceptors.response.use(
  r => {
    return r.data.data
  },
  e => {
    if (e.response.status === 422) {
      let errors = []
      forIn(e.response.data.errors, function(v, i) {
        errors[i] = {
          state: true,
          label: v[0] // or only v
        }
      })
      return Promise.reject({
        status: 422,
        data: errors
      })
    }
  }
)
...
const user = {
  register(params) {
    return api.post('/api/auth/signup', params)
  },
  login(params) {
    return api.post('/api/auth/login', params)
  }
}

export {
  user
}
...

@beggiatom thank you for sharing!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chriswa picture chriswa  路  3Comments

smousa picture smousa  路  3Comments

milleraa picture milleraa  路  3Comments

cawa-93 picture cawa-93  路  3Comments

dschreij picture dschreij  路  3Comments