Form Validation

Usage

rules prop allows validation of form components. rules is an object where each prop is a name of global validator or user defined function with tested value as argument. User functions should return true for valid result or the string message if the result is invalid. Global validators include:

  • required
  • alpha
  • numeric
  • alphanumeric
  • minLength
  • maxLength
  • minElements
  • maxElements
  • minValue
  • maxValue
  • email
  • atLeastOneUppercase
  • atLeastOneLowercase
  • atLeastOneDigit
  • atLeastOneSpecial
  • sameAs

Default messages of global validators can be changed by setValidationMessage(validator, message) function. If validator has argument (for example maxLength) %d token can be used in message in place of that argument.

    import { setValidationMessage } from "vue-components"

setValidationMessage("maxLength", "Please enter up to %d characters")

  

Example - simple validation

      model: ""
      rules: [
	"required",
	{
		"minLength": 5
	},
	"alphanumeric"
]
      status: {
	"required": false,
	"minLength": false,
	"alphanumeric": false,
	"valid": false,
	"optional": false,
	"touched": false,
	"validated": false,
	"dirty": false
}
    
    <template>
  <div class="flex flex-col md:flex-row md:gap-x-20">
    <div class="basis-1/2">
      <v-input
        v-model="username"
        :rules="usernameRules"
        type="text"
        placeholder="Username"
        block
        class="w-full"
        @validation:status="(status) => (usernameStatus = status)"
      ></v-input>
    </div>
    <pre class="m-0 mt-[100px] md:mt-0">
      <code v-html="'model: ' + stringifyObject(username)"></code>
      <code v-html="'rules: ' + stringifyObject(usernameRules)"></code>
      <code v-html="'status: ' + stringifyObject(usernameStatus, true)"></code>
    </pre>
  </div>
</template>
  
    <script setup>
import { ref } from "vue";
import { stringifyObject } from "../tools";

let username = ref("");
let usernameStatus = ref({});
let usernameRules = [
  "required",
  { minLength: 5 },
  "alphanumeric",
];
</script>
  
      model: ""
      rules: [
	"required",
	"atLeastOneUppercase",
	"atLeastOneLowercase",
	"atLeastOneSpecial",
	"atLeastOneDigit",
	{
		"minLength": 8
	}
]
      status: {
	"required": false,
	"atLeastOneUppercase": false,
	"atLeastOneLowercase": false,
	"atLeastOneSpecial": false,
	"atLeastOneDigit": false,
	"minLength": false,
	"valid": false,
	"optional": false,
	"touched": false,
	"validated": false,
	"dirty": false
}
    
    <template>
  <div class="flex flex-col md:flex-row md:gap-x-20">
    <div class="basis-1/2">
      <v-input
        v-model="password"
        :rules="passwordRules"
        type="text"
        placeholder="Password"
        block
        class="w-full"
        @validation:status="(status) => (passwordStatus = status)"
      ></v-input>
    </div>
    <pre class="m-0 mt-[100px] md:mt-0">
      <code v-html="'model: ' + stringifyObject(password)"></code>
      <code v-html="'rules: ' + stringifyObject(passwordRules)"></code>
      <code v-html="'status: ' + stringifyObject(passwordStatus, true)"></code>
    </pre>
  </div>
</template>
  
    <script setup>
import { ref } from "vue";
import { stringifyObject } from "../tools";

let password = ref("");
let passwordStatus = ref({});
let passwordRules = [
  "required",
  "atLeastOneUppercase",
  "atLeastOneLowercase",
  "atLeastOneSpecial",
  "atLeastOneDigit",
  { minLength: 8 },
];
</script>
  
      model: []
      rules: [
	"required",
	{
		"minElements": 3
	},
	{
		"maxElements": 5
	}
]
      status: {
	"required": false,
	"minElements": false,
	"maxElements": true,
	"valid": false,
	"optional": false,
	"touched": false,
	"validated": false,
	"dirty": false
}
    
    <template>
  <div class="flex flex-col md:flex-row md:gap-x-20">
    <div class="basis-1/2 pl-4">
      <v-checkbox-group
        v-model="languages"
        :rules="languagesRules"
        ref="group"
        validate-mode="form-silent"
        @validation:status="(status) => (languagesStatus = status)"
      >
        <div
          v-for="l in languagesData"
          class="my-2"
        >
          <v-checkbox
            :value="l"
            :id="'language-' + l"
            :label="l"
          ></v-checkbox>
        </div>
      </v-checkbox-group>
      <v-button
        class="mt-10 mr-4"
        mod-button="variant:secondary"
        @click="group.reset()"
      >
        Reset
      </v-button>
      <v-button
        class="mt-10"
        @click="group.validate()"
      >
        Validate
      </v-button>
    </div>
    <pre class="m-0 mt-[20px] md:mt-0">
      <code v-html="'model: ' + stringifyObject(languages)"></code>
      <code v-html="'rules: ' + stringifyObject(languagesRules)"></code>
      <code v-html="'status: ' + stringifyObject(languagesStatus, true)"></code>
    </pre>
  </div>
</template>
  
    <script setup>
import { ref } from "vue";
import { stringifyObject } from "../tools";

let languages = ref([]);
let languagesStatus = ref({});
let languagesRules = [
  "required",
  { minElements: 3 },
  { maxElements: 5 },
];

let group = ref(null);

let languagesData = ref([
  "english",
  "swedish",
  "korean",
  "german",
  "icelandic",
  "japanese",
]);
</script>
  

Example - validation modes

validation-on and validation-mode allows control over when to start validation and how to update state according to validation results:

  • validate-on: "blur" - validate after input loses focus (default)
  • validate-on: "immediate" - starts validating immediately after first input
  • validate-on: "form" - validate after calling validate function of form component
  • validate-mode: "silent" - valid values does not change input state unless it was invalid before (only for validate on blur) (default)
  • validate-mode: "eager" - invalid and valid values always change input state

      
  • validate-on: "blur"
  • validate-mode: "silent""
model: "" rules: [ "required", { "minLength": 5 }, "alphanumeric" ] status: { "required": false, "minLength": false, "alphanumeric": false, "valid": false, "optional": false, "touched": false, "validated": false, "dirty": false }

      
  • validate-on: "blur"
  • validate-mode: "eager""
model: "" rules: [ "required", { "minLength": 5 }, "alphanumeric" ] status: { "required": false, "minLength": false, "alphanumeric": false, "valid": false, "optional": false, "touched": false, "validated": false, "dirty": false }

      
  • validate-on: "immediate"
  • validate-mode: "eager""
model: "" rules: [ "required", { "minLength": 5 }, "alphanumeric" ] status: { "required": false, "minLength": false, "alphanumeric": false, "valid": false, "optional": false, "touched": false, "validated": false, "dirty": false }

Example - form validation

In order to validate entire form wrap inputs with v-form component which exposes two functions: validate() and reset(). Calling validate() function validates every input according to its rules and return true if all are valid (false if any input is invalid). To reset all inputs within v-form use exposed reset() function.

      username: {
	"valid": false,
	"validated": false
}
      password: {
	"valid": false,
	"validated": false
}
      text: {
	"valid": false,
	"validated": false
}
      form validate(): false
    
    <template>
  <div class="flex gap-x-20">
    <div class="flex basis-1/2 flex-col">
      <v-form
        ref="form"
        class="flex flex-col"
      >
        <div>
          <v-input
            v-model="inputs.username"
            type="text"
            label="Username"
            :rules="usernameRules"
            block
            class="w-full"
            @validation:status="(res) => (status.username = res)"
          ></v-input>
        </div>

        <div class="mt-20">
          <v-input
            v-model="inputs.password"
            type="text"
            label="Password"
            :rules="passwordRules"
            block
            class="w-full"
            @validation:status="(res) => (status.password = res)"
          ></v-input>
        </div>

        <div class="mt-32">
          <v-textarea
            v-model="inputs.text"
            :rules="textRules"
            placeholder="Some text"
            rows="3"
            @validation:status="(res) => (status.text = res)"
          ></v-textarea>
        </div>

        <div class="mt-10">
          <v-checkbox
            v-model="inputs.checkbox"
            :rules="checkboxRules"
            label="Check this"
          />
        </div>
      </v-form>

      <div class="mt-20 self-end">
        <v-button
          mod-button="variant:secondary"
          @click="form.reset()"
          class="mr-4"
        >
          Reset
        </v-button>
        <v-button @click="validate()">Validate</v-button>
      </div>
    </div>

    <!-- validation results -->

    <pre class="m-0">
      <code v-html="'username: ' + stringifyObject(status.username, true, ['valid', 'validated'])"></code>
      <code v-html="'password: ' + stringifyObject(status.password, true, ['valid', 'validated'])"></code>
      <code v-html="'text: ' + stringifyObject(status.text, true, ['valid', 'validated'])"></code>
      <code v-html="'form validate(): ' + stringifyObject(status.form, true)"></code>
    </pre>
  </div>
</template>
  
    <script setup>
import { ref, reactive } from "vue";
import { stringifyObject } from "../tools";

let inputs = reactive({
  username: "",
  password: "",
  text: "",
  checkbox: false,
});

let usernameRules = [
  "required",
  { minLength: 5 },
  "alphanumeric"
];

let passwordRules = [
  "required",
  { minLength: 8 },
  "atLeastOneUppercase",
  "atLeastOneLowercase",
  "atLeastOneSpecial",
  "atLeastOneDigit",
];

let textRules = [
  "required",
  { maxLength: 30 }
];

let checkboxRules = ["required"];

let form = ref(null);

let validate = () => {
  status.form = form.value.validate();
};

let status = reactive({
  username: {},
  password: {},
  text: {},
  checkbox: {},
  form: false,
});
</script>