Categories
Vue

Vee-Validate — Validation States and Form Validation

Form validation is a feature that’s not built into Vue.js.

However, we still need this feature very much.

In this article, we’ll look at how to use check and display validation states.

Also, we look at how to validate a whole form.

Validation State

In addition to displayingerrors , we can check the validation state of the form.

Flags

There are many validation flags available. They include:

  • valid — check if the field is valid
  • invalid — check if a field is invalid
  • changed — check if a field is changed
  • touched — check if a field ha been blurred
  • untouched — check if a field isn’t blurred
  • pristine — check if field value isn’t manipulated
  • dirty — check if field value is manipulated
  • pending — indicates if field validation in progress
  • required — check if a field is required
  • validated — check if a field is validated at least once
  • passed — check if a field has been validated and it’s valid
  • failed — check if a field has been validated and it’s invalid

They are available as slot props.

So we can use them by writing:

main.js

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";
import { required } from "vee-validate/dist/rules";

extend("required", required);
Vue.component("ValidationProvider", ValidationProvider);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <ValidationProvider rules="required" v-slot="{ valid }">
      <input v-model="value" type="text">
      <span>{{ valid }}</span>
    </ValidationProvider>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      value: ""
    };
  }
};
</script>

We just get valid from v-slot , and display the value of it below it.

Handling Forms

In addition to checking the form validation state, we can also check if all of a form’s values are valid before submission.

For example, we can write:

main.js

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, ValidationObserver, extend } from "vee-validate";
import { required, alpha } from "vee-validate/dist/rules";

extend("required", required);
extend("alpha", alpha);

Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);

Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <ValidationObserver v-slot="{ handleSubmit }">
      <form [@submit](http://twitter.com/submit "Twitter profile for @submit").prevent="handleSubmit(onSubmit)">
        <ValidationProvider rules="required|alpha" v-slot="{ errors }">
          <input v-model="name" name="name" type="text">
          <span>{{ errors[0] }}</span>
        </ValidationProvider>
        <input type="submit" value="submit">
      </form>
    </ValidationObserver>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      name: ""
    };
  },
  methods: {
    onSubmit() {
      alert("submitted");
    }
  }
};
</script>

We imported the required and alpha rules.

Also, we imported the ValidationObserver component in addition to ValidationProvider .

We nest ValidationProvider in the ValidationObserver to watch for the validation states of all fields.

The form tag has the submit handler, it’s created by getting the handleSubmit function.

Then we pass in our own onSubmit method to it.

Now when we enter alphabetic data, then we’ll see the ‘submitted’ alert.

This means onSubmit is called.

Otherwise, onSubmit won’t be called.

If it’s not called, then at least some form values aren’t valid.

Programmatic Access with $refs

We can access the form validation state with refs.

For example, we can rewrite the example by writing the following code:

<template>
  <div id="app">
    <ValidationObserver ref="form">
      <form [@submit](http://twitter.com/submit "Twitter profile for @submit").prevent="onSubmit">
        <ValidationProvider rules="required|alpha" v-slot="{ errors }">
          <input v-model="name" name="name" type="text">
          <span>{{ errors[0] }}</span>
        </ValidationProvider>
        <input type="submit" value="submit">
      </form>
    </ValidationObserver>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      name: ""
    };
  },
  methods: {
    async onSubmit() {
      const success = await this.$refs.form.validate();
      if (!success) {
        return;
      }
      alert("submitted");
      this.$nextTick(() => {
        this.$refs.form.reset();
      });
    }
  }
};
</script>

We set the ref as the 'form' .

Our onSubmit method when we click submit on the form.

Then in onSubmit , we check for form validity by running the validate method on this.$refs.form .

It returns a promise that has the success value. It resolves to true if the form is valid.

Otherwise, it’s false .

Therefore, is success is false , we stop running onSubmit .

If the form is valid, we show a ‘submitted’ alert.

We reset the value of this.name .

And we reset the form validation state with this.$refs.form.reset(); in the next render iteration with this.$nextTick .

Conclusion

We can use Vee-Validate to check the validation state of a whole form.

To do this, we use the ValidationObserver component to watch the validation state of the form.

We can check with the built-in handleSubmit function or by assigning a ref to ValidationObserver .

Categories
Vue

Vee-Validate — Built-in Validation Rules

Form validation is a feature that’s not built into Vue.js.

However, we still need this feature very much.

In this article, we’ll look at how to use built-in validation rules that take arguments.

Rules

Many rules take one or more arguments.

digits

digits can be used as follows:

<ValidationProvider rules="digits:10" v-slot="{ errors }">
  <input v-model="value" type="text">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

where 10 is the number of digits allowed

dimensions

dimensions checks the dimensions of the image file selected:

<ValidationProvider rules="dimensions:220,230" v-slot="{ errors, validate }">
  <input type="file" @change="validate">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

220 is the width and 230 is the height.

excluded

excluded checks if something isn’t in the list:

<ValidationProvider rules="excluded:1,2" name="number" v-slot="{ errors }">
  <select v-model="value">
    <option value="1">one</option>
    <option value="2">two</option>
    <option value="3">three</option>
  </select>
  <span>{{ errors[0] }}</span>
</ValidationProvider>

1 and 2 are arguments of excluded , so they’re invalid.

ext

ext checks if a selected file has the given extension specified:

<ValidationProvider rules="ext:jpg,png" v-slot="{ errors, validate }">
  <input type="file" @change="validate">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

So jpg and png are valid file extensions.

is_not

is_not takes an argument to exclude.

For example, we can write:

<ValidationProvider rules="is_not:foo" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

foo is the value that’s not valid when entered.

length

length means that the string must be a string or array value that must have the given length.

Therefore, if we have:

<ValidationProvider rules="length:5" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

Then the inputted value must have length 5.

max

max checks if the inputted value doesn’t exceed the specified length.

For example, we can write:

<ValidationProvider rules="max:5" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

We have 5 as the argument, so the inputted value can’t exceed the length of 5.

max_value

max_value checks if something can’t exceed the maximum value.

We can write:

<ValidationProvider rules="max_value:5" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

mimes

mimes checks the selected file has the given mime type.

For example, we can write:

<ValidationProvider rules="mimes:image/*" v-slot="{ errors, validate }">
  <input type="file" @change="validate">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

This will check the file is an image.

min

min is the validation length shouldn’t be less than the specified length.

If we have:

<ValidationProvider rules="min:5" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

Then the inputted value must have a length 5 or longer.

min_value

min_value checks if a numeric value is bigger than or equal to the given argument.

For example, if we have:

<ValidationProvider rules="min_value:5" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

Then value must be bigger than or equal to 5.

oneOf

oneOf takes one or more arguments to check if the selected value is one of the listed values.

If we have:

<ValidationProvider rules="oneOf:1,2,3" name="number" v-slot="{ errors }">
  <select v-model="value">
    <option value="1">one</option>
    <option value="2">two</option>
    <option value="3">three</option>
    <option value="4">hour</option>
  </select>
  <span>{{ errors[0] }}</span>
</ValidationProvider>

We have 1, 2, and 3 as the arguments, so they are the only valid values.

regex

regex lets us match a value that matches the given regex.

If we have:

<ValidationProvider :rules="{ regex: /^[0-9]+$/ }" v-slot="{ errors }">
  <input type="text" v-model="value">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

then we match the regex /^[0–9]+$/ which is a string with digits.

required

The required field can take an object with the allowFalse property, which is true if we want to allow false as a valid value.

For example, to allow false as a valid value when we use the required rule, we write:

<ValidationProvider :rules="{ required: { allowFalse: false } }" v-slot="{ errors }">
  <!-- ... -->
</ValidationProvider>

required_if

required_if lets us check if a field is required if another field has the given value.

For instance, we can use it by writing:

<ValidationProvider rules="" vid="country" v-slot="{ errors }">
  <select v-model="country">
    <option value="Canada">Canada</option>
    <option value="other">Other country</option>
  </select>
</ValidationProvider>

<ValidationProvider rules="required_if:country,Canada" v-slot="{ errors }">
  <input type="text" placeholder="province" v-model="province" />
  <span>{{ errors[0] }}</span>
</ValidationProvider>

We have the vid on the first field so that we can reference it in the field below.

required_if references the vid value.

The second argument is the value.

size

size is used to check if a file exceeds the given size in kilobytes.

We can write:

<ValidationProvider rules="size:100" v-slot="{ errors, validate }">
  <input type="file" @change="validate">
  <span>{{ errors[0] }}</span>
</ValidationProvider>

validate is used to check the value when the file selection changes.

Conclusion

There are many built-in validation rules.

Some of them take arguments. There are rules to check file sizes and input values.

Categories
Vue

Vee-Validate — Messages and Required Fields

Form validation is a feature that’s not built into Vue.js.

However, we still need this feature very much.

In this article, we’ll look at how to display validation messages and defining required fields.

Field Name Placeholder

We can add a form field name placeholder with the {_field_} placeholder in our validation message.

For instance, we can write:

extend("positive", value => {
  if (value >= 0) {
    return true;
  }
  return "please enter a positive number for `{_field_}`";
});

Then we can use it by writing:

<template>
  <div>
    <ValidationProvider name="age" rules="positive" v-slot="{ errors }">
      <input v-model="age" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      age: undefined
    };
  }
};
</script>

If we enter something that’s not a positive number, we’ll see the message ‘please enter a positive number for age’.

{_field_} is replaced with the value of the name prop in ValidationProvider .

If the name prop isn’t on ValidationProvider , it can also use the value of the input’s name attribute.

For example, we can write:

<template>
  <div>
    <ValidationProvider name="age" rules="positive" v-slot="{ errors }">
      <input v-model="value" name="age" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      age: undefined
    };
  }
};
</script>

We’ll get the same result in both cases.

Arguments Placeholders

We can also add placeholders in our validation for arguments.

For example, we can write:

extend("min", {
  validate(value, { min }) {
    return value.min >= min;
  },
  params: ["min"],
  message: "please enter at least {min} for {_field_}"
});

We used the object instead of the function for validation.

Other placeholders include _value_ with the value entered.

_rule_ is the rule name that triggered the message.

This way, we set the params property to get the arguments of the rule in the 2nd parameter of validate as an object with the min property in it.

Then we can add the placeholder for min as we did in the string we set for the message property.

Then we can use it by writing:

<template>
  <div>
    <ValidationProvider name="age" rules="min:10" v-slot="{ errors }">
      <input v-model="age" name="age" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      age: undefined
    };
  }
};
</script>

Now when we enter something less than 10, we get the error message ‘please enter at least 10 for age’.

Messages as Functions

The message property can be a method that returns a string.

For example, we can replace what we had with:

extend("min", {
  validate(value, { min }) {
    return value >= min;
  },
  params: ["min"],
  message: (fieldName, placeholders) => {
    return `please enter at least ${placeholders.min} for ${fieldName}`;
  }
});

We replace the message string with a method that has the fieldName with the input field name.

The 2nd parameter is the placeholders , which is the same as args in the validate method.

Therefore, we get the same result as we have in the previous example.

Multiple Messages

By default, Vee-Validate stops validation when it encounters the first rule in the list that failed validation.

We can make Vee-Validate run all the validation rules on the list.

To do that we can set the bails prop to false .

For example, if we have:

extend("min", {
  validate(value, { min }) {
    return +value >= +min;
  },
  params: ["min"],
  message: "too small"
});

extend("odd", {
  validate: value => {
    return value % 2 !== 0;
  },
  message: "not odd"
});

Then we can add a field by writing:

<template>
  <div>
    <ValidationProvider name="value" :bails="false" rules="min:10|odd" v-slot="{ errors }">
      <input v-model="value" type="text">
      <span>{{ errors.join('. ') }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      value: undefined
    };
  }
};
</script>

We set bails to false so that both rules will always be run.

We called join to join the errors entries together.

If we enter 2, then we’ll see ‘too small. not odd’ displayed.

Conclusion

We can add placeholders for field names and argument names.

Also, we can make all validation rules run even if the earlier ones failed.

Validation messages can also be generated by a function.

Categories
Vue

Getting Started with Vue Form Validation with Vee-Validate

Form validation is a feature that’s not built into Vue.js.

However, we still need this feature very much.

In this article, we’ll look at how to add basic form validation with the Vee-Validate library.

Getting Started

We can get started by install the package.

To install it, we run:

npm install vee-validate --save

Then we can register the ValidationProvider plugin by writing:

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider } from "vee-validate";

Vue.component("ValidationProvider", ValidationProvider);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

in main.js .

This way, we can use it throughout our app.

We can also import extend to cretye our own validation rules:

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";

extend("secret", {
  validate: value => value === "secret",
  message: "wrong word"
});

Vue.component("ValidationProvider", ValidationProvider);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

value has the inputted value and we return true if it’s valid and false otherwise.

message is the form validation error message that we’ll display.

Vue.component(“ValidationProvider”, ValidationProvider);

will make the ValidationProvider component available globally.

Basic Usage

We can add the ValidationProvider component int our app by writing:

<template>
  <div>
    <ValidationProvider rules="secret" v-slot="{ errors }">
      <input v-model="email" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data(){
    return {
      email: ''
    }
  }
};
</script>

If we type in ‘secret’, then we’ll see nothing.

Otherwise, we’ll see the error message ‘wrong word’ that we set earlier.

errors has the error messages returned by the validator that we have before.

Component Registration

If we just want to use the ValidationProvider component in one component, we can write:

import { ValidationProvider } from 'vee-validate';

export default {
  components: {
    ValidationProvider
  }
};

to register ValidationProvider in the component.

Rule Arguments

We can add arguments to rules.

For instance, we can write:

extend("minLength", {
  validate(value, args) {
    return value.length >= args.length;
  },
  params: ["length"],
  message: "too short"
});

We have a validate method that has the args parameter.

args can have any property specified by the params property.

Therefore, in this case, we can have the length property ion args .

To use it, we can write:

<template>
  <div>
    <ValidationProvider rules="minLength:5" v-slot="{ errors }">
      <input v-model="value" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      value: ""
    };
  }
};
</script>

We have:

minLength:5

to set args.length to 5.

So we’ll get an error message if value ‘s length is less than 5.

Multiple Arguments

We can have multiple arguments in our validate method.

For example, we can write:

extend("length", {
  validate(value, { min, max }) {
    return value.length >= min && value.length <= max;
  },
  params: ["min", "max"],
  message: "too short"
});

Then we can use it by writing:

<template>
  <div>
    <ValidationProvider rules="length:5,10" v-slot="{ errors }">
      <input v-model="value" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      value: ""
    };
  }
};
</script>

We restructured args into min and max in the arguments.

Then we pass in the arguments separated by a comma.

Then if we enter something that’s shorter than 5 characters or longer than 10, we’ll see an error message.

Vee-Validate will automatically pass in any number of parameters and put it in args.

But putting the property names in params will let us get the by the key instead of getting them as an array.

So we can write something like:

rules="one_of:1,2,3,4,5,6,7,8"

and args will have [1, 2, 3, 4, 5, 6, 7, 8] if we defined a validate method for the one_of rule.

Messages

We can return the message in the validation function as an alternative to setting them in message .

For instance, we can write:

import Vue from "vue";
import App from "./App.vue";
import { ValidationProvider, extend } from "vee-validate";

extend("positive", value => {
  if (value >= 0) {
    return true;
  }
  return "please enter a positive number";
});
Vue.component("ValidationProvider", ValidationProvider);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

Then we can write:

<template>
  <div>
    <ValidationProvider rules="positive" v-slot="{ errors }">
      <input v-model="value" type="text">
      <span>{{ errors[0] }}</span>
    </ValidationProvider>
  </div>
</template>
<script>
export default {
  data() {
    return {
      value: ""
    };
  }
};
</script>

and we’ll see the ‘please enter a positive number’ displayed if we enter anything other than a positive number.

Conclusion

Vee-Validate is an easy to use package for adding form validation capabilities to a Vue app.

It’s much easier than validating inputs with our own code.

Categories
Vue

Create a Dropdown with Vue-MultiSelect

A dropdown is often something we want to add in Vue apps.

To make our lives easier, we can use a component library to add it.

In this article, we’ll look at how to create a dropdown with Vue-MultiSelect

Getting Started

We can install Vuetify by running:

npm install vue-multiselect --save

Then we can use it by writing:

import Vue from "vue";
import App from "./App.vue";
import Multiselect from "vue-multiselect";
Vue.component("multiselect", Multiselect);
Vue.config.productionTip = false;

new Vue({
  render: h => h(App)
}).$mount("#app");

in main.js .

We add the following to our index.html file:

<link
  rel="stylesheet"
  href="https://unpkg.com/vue-multiselect@2.1.0/dist/vue-multiselect.min.css"
/>

Then we can use it in App.vue by writing:

<template>
  <div id="app">
    <multiselect v-model="value" :options="options"></multiselect>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: null,
      options: ["foo", "bar", "baz"]
    };
  }
};
</script>

We registered the multiselect component globally with:

import Multiselect from "vue-multiselect";
Vue.component("multiselect", Multiselect);

Therefore, we can use it anywhere.

The options prop takes an array of options.

v-model binds to the selected value.

Now we should see a dropdown with the options listed in options .

Other props include searchables , which lets us type in something to search for it.

placeholder lets us add a placeholder.

close-on-select lets us choose whether the menu closes when an item is selected.

allow-empty indicates whether we want to let users deselect a value of it’s selected.

deselect-label lets us add a message to display if a user tries to deselect an item.

We can write:

<template>
  <div id="app">
    <multiselect v-model="value" deselect-label="Can't remove this value" :options="options"></multiselect>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: null,
      options: ["foo", "bar", "baz"]
    };
  }
};
</script>

to add the deselect-label option.

Select with Search

We can let users select an item by typing with the searchable prop.

We can add a custom-label prop to lets us pass in a function return a string to display a custom label.

For example, we can write:

<template>
  <div id="app">
    <multiselect v-model="value" searchable :custom-label="nameWithLang" :options="options"></multiselect>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: null,
      options: [
        { name: "Vue.js", language: "JavaScript" },
        { name: "React", language: "JavaScript" },
        { name: "Rails", language: "Ruby" }
      ]
    };
  },
  methods: {
    nameWithLang({ name, language }) {
      return `${name} — ${language}`;
    }
  }
};
</script>

We have the searchable prop so users can select by typing.

And we have the custom-label prop set to the nameWithLang as the value.

So that’ll be displayed as the value.

Multiple Select

We can enable multiple selections with the multiple prop.

For example, we can write:

<template>
  <div id="app">
    <multiselect v-model="value" multiple :custom-label="nameWithLang" :options="options"></multiselect>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: null,
      options: [
        { name: "Vue.js", language: "JavaScript" },
        { name: "React", language: "JavaScript" },
        { name: "Rails", language: "Ruby" }
      ]
    };
  },
  methods: {
    nameWithLang({ name, language }) {
      return `${name} — ${language}`;
    }
  }
};
</script>

Then we can select multiple items from the list.

We can populate the tag slot with our own content for the dropdown items.

For instance, we can write:

<template>
  <div id="app">
    <multiselect v-model="value" multiple :options="options">
      <template slot="selection" slot-scope="{ values, search, isOpen }">
        <span
          v-if="values.length && !isOpen"
        >{{ values.length }} options selected</span>
      </template>
    </multiselect>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: null,
      options: ["Vue.js", "React", "Rails"]
    };
  }
};
</script>

Then we’ll see the number of options we selected.

values has the selected values.

Asynchronous Select

Dropdown options can be loaded asynchronously.

To do that, we can add the loading prop to indicate when it’s loading.

options-limit lets us set the maximum number of options.

limit lets us limit the number of visible results.

internal-search enables or disables the library’s internal search engine.

hide-selected lets us display the items or not.

For example, we can write:

<template>
  <div id="app">
    <multiselect v-model="value" :limit="2" :loading="loading" :options="options"></multiselect>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: null,
      options: []
    };
  },
  mounted() {
    this.loading = true;
    setTimeout(() => {
      this.options = ["Vue.js", "React", "Rails"];
      this.loading = false;
    }, 100);
  }
};
</script>

Then we set the loading prop to indicate that the items are being loaded.

Conclusion

We can create a dropdown easily with Vue-Multiselect.

All we have to do is to add the plugin and use the built-in component.