Search code examples
javascriptvue.jsinputkeypress

Disable keypress on numbers greater than 3 digits


I have this code, I would like to prevent the user from entering if the number of digits entered is greater than 3. So if the user writes for example 150 it is fine, if he tries to write a number with 4 or more digits: such as 1601 then the code should prevent this.

So it must disable the keypress.

<template>
  <b-form-input type="number" v-model="number" @input="getPeople(number)">
  </b-form-input>
</template>

<script>
  export default {
    data() {
      return {
        number: "",
      };
    },
    getPeople(text) {
      if (text.length >= 3) {
        text.preventDefault();
      }
    },
  };
</script>

As of right now the code doesn't work and here is what the error says:

 v-on handler: "TypeError: text.preventDefault is not a function"

Solution

  • The best possible UI/UX is not to prevent the user from entering invalid data, but to tell them why it's invalid, when it is. If you're interested into why that's the case, it's a long discussion and this is probably not the best place to outline it. But it boils down to: treat your users with the maximum possible amount of respect. Disallowing typing contradicts that principle.

    Getting back to your example, the basic way to handle it is using max attribute:

    <b-form-input
      type="number"
      v-model="number"
      max="999"
      @input="getPeople(number)" />
    

    If you want more control over how the validation message is displayed and when validation is triggered, you could use a validation plugin outlined in BootstrapVue's documentation (since you use BV).

    Note you'll need to update the markup to match the preferred validation plugin's requirements.


    If you (or your client) really want(s) to call preventDefault() on the input event, according to BV documentation

    You can always access the native input and change events by using the .native modifier.

    you will have to apply the .native modifier in order to get the native event as param. Otherwise you'll only get the value.

    <b-form-input
      type="number"
      v-model="number"
      @input.native="getPeople" />
    

    and modify getPeople to:

    methods: {
      getPeople(event) {
        if (event.target.value >= 1e3) {
          event.preventDefault();
          this.number = 999;
        }
      }
    }
    

    See it working:

    let memory = 0;
    
    new Vue({
      el: '#app',
      data: () => ({
        number: 0
      }),
      methods: {
        getPeople(event) {
          if (event.target.value >= 1e3) {
            event.preventDefault();
            this.number = memory;
          } else {
            memory = event.target.value;
          }
        }
      }
    })
    <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"></script>
    <script src="//unpkg.com/vue@latest/dist/vue.min.js"></script>
    <script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
    
    <div id="app" class="m-5">
      <b-form-input type="number" v-model="number" @input.native="getPeople" />
    </div>