Search code examples
validationvuejs2blurbootstrap-vue

Vue-Bootstrap b-form-input state on blur rather than load


I'm using Vue-Bootstrap and I have a b-form-input in my component that is a password. I check the validation on this input for the password being at least 8 characters long:

<b-form-group
        label="Password: (8 characters minimum)"
        minlength="8"
        class="text-left  mt-3"
      >
        <b-form-input
          v-model="form.password"
          type="password"
          name="password"
          placeholder="Enter Your Password"
          :state="passwordState"
          pattern=".{8,}"
          description="please enter a password "
          title="Password should be at least 8 characters long"
          required
        ></b-form-input>
        <b-form-invalid-feedback :state="passwordState">
          Your password must be at least 8 characters long.
        </b-form-invalid-feedback>
      </b-form-group>
      <b-form-group
        was-validated
        label="Confirm Password:"
        class="text-left  mt-3"
      >
        <b-form-input
          type="password"
          v-model="form.confirmpassword"
          placeholder="Confirm Your Password"
          required
          :state="confirmPasswordState"
          pattern=".{8,}"
        ></b-form-input>
        <b-form-invalid-feedback :state="confirmPasswordState">
          Your confirmed password must be exactly the same as your password
          field.
        </b-form-invalid-feedback>
      </b-form-group>
 computed: {
    confirmPasswordState() {
      return this.form.password == this.form.confirmpassword &&
        this.form.confirmpassword != ""
        ? true
        : false;
    },
    passwordState() {
      return this.form.password.length >= 8 ? true : false;
    },
  },

I only want this state validation to show up on blur and not on load.


Solution

  • I think the easiest way to do this is to add a flag in data to track whether an input has blurred, and then make validation conditional based on that flag.

    1. Add passwordHasBlurred: false to data()
    2. Add @blur="passwordHasBlurred = true" to both of your <b-form-input>s:
      • <b-form-input
           ...
           @blur="passwordHasBlurred = true"
        >
        
    3. Adjust your computed validation functions to return null when passwordHasBlurred is false. This tells Bootstrap-Vue to display no validation state on either input before one is blurred.
      • passwordState() {
          return this.passwordHasBlurred
            ? this.form.password.length >= 8
              ? true
              : false
            : null;
        },
        
      • confirmPasswordState() {
          return this.passwordHasBlurred 
            ? this.form.password == this.form.confirmpassword &&
             this.form.confirmpassword != "" 
             ? true 
             : false
            : null;
        },
        

    And here's a runnable example! (Hidden because of its size):

    new Vue({
      el: '#app',
      data() {
        return {
          form: {
            password: '',
            confirmPassword: '',
          },
          passwordHasBlurred: false,
        }
      },
      computed: {
        confirmPasswordState() {
          return this.passwordHasBlurred 
            ? this.form.password == this.form.confirmpassword &&
             this.form.confirmpassword != "" 
             ? true 
             : false
            : null;
        },
        passwordState() {
          return this.passwordHasBlurred
            ? this.form.password.length >= 8
              ? true
              : false
            : null;
        },
      },
      methods: {
        reset() {
          this.form.password = '';
          this.form.confirmPassword = '';
          this.passwordHasBlurred = false;
        },
      },
    });
    body {
      padding: 1rem;
    }
    <!-- Add Vue and Bootstrap-Vue to snippet -->
    <link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" /><link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css" /><script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script><script src="//unpkg.com/vue@2/dist/vue.min.js"></script><script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
    
    <template id="app">
      <div>
        <b-form-group
          label="Password: (8 characters minimum)"
          minlength="8"
          class="text-left  mt-3"
        >
          <b-form-input
            v-model="form.password"
            type="password"
            name="password"
            placeholder="Enter Your Password"
            :state="passwordState"
            pattern=".{8,}"
            description="please enter a password "
            title="Password should be at least 8 characters long"
            required
            @blur="passwordHasBlurred = true"
          ></b-form-input>
          <b-form-invalid-feedback :state="passwordState">
            Your password must be at least 8 characters long.
          </b-form-invalid-feedback>
          </b-form-group>
          <b-form-group
            label="Confirm Password:"
            class="text-left  mt-3"
          >
          <b-form-input
            type="password"
            v-model="form.confirmpassword"
            placeholder="Confirm Your Password"
            required
            :state="confirmPasswordState"
            pattern=".{8,}"
            @blur="passwordHasBlurred = true"
          ></b-form-input>
          <b-form-invalid-feedback :state="confirmPasswordState">
            Your confirmed password must be exactly the same as your password
            field.
          </b-form-invalid-feedback>
        </b-form-group>
        <br>
        <b-btn variant="outline-secondary" @click="reset">
          Reset
        </b-btn>
      </div>
    </template>

    If you want or need to track each input's blurring separately, just add another property to data for tracking and adjust the computed property and event handlers accordingly.