Tag Archives: vuejs

vue-pin-code-input-component

Vue PIN code input component

At the end of this post you’ll learn how to implement a basic vue pin code input component.

One of my projects required an authorization layer for protecting some resources.

I ended up building a quite simple Vue Component that can be integrated in any app and that can be easily extended for any needs.

The template of the Vue Pin Code Component looks like this:

<template>
    <div>
        <div class="input-group">
            <input v-model.number="pin_0"
                   v-on:keyup.right="pin_focus('pin_1')"
                   v-on:keypress="is_valid_pin_value($event, 'pin_0')"
                   ref="pin_0" type="text" placeholder="0">
            <input v-model.number="pin_1"
                   v-on:keyup.left="pin_focus('pin_0')"
                   v-on:keyup.right="pin_focus('pin_2')"
                   v-on:keypress="is_valid_pin_value($event, 'pin_1')"
                   ref="pin_1" type="text" placeholder="0"">
            <input v-model.number="pin_2"
                   v-on:keyup.left="pin_focus('pin_1')"
                   v-on:keyup.right="pin_focus('pin_3')"
                   v-on:keypress="is_valid_pin_value($event, 'pin_2')"
                   ref="pin_2" type="text" placeholder="0">
            <input v-model.number="pin_3"
                   v-on:keyup.left="pin_focus('pin_2')"
                   v-on:keypress="is_valid_pin_value($event, 'pin_3')"
                   ref="pin_3" type="text" placeholder="0">
        </div>
    </div>
</template>

The controller of the component:

export default {
     data: function () {
         return {
             pin_0: null,
             pin_1: null,
             pin_2: null,
             pin_3: null
         }
     },
     computed: {
         pin: function () {
             return ${this.pin_0}${this.pin_1}${this.pin_2}${this.pin_3}
         }
     },
     watch: {
         pin: function () {
             this.$bus.$emit('PIN/change', this.pin)
         },
         pin_0: function (nv) {
             if (nv.toString().length !== 0) {
                 this.$refs.pin_1.focus()
                 this.$refs.pin_1.select()
             }
         },
         pin_1: function (nv) {
             if (nv.toString().length !== 0) {
                 this.$refs.pin_2.focus()
                 this.$refs.pin_2.select()
             }
         },
         pin_2: function (nv) {
             if (nv.toString().length !== 0) {
                 this.$refs.pin_3.focus()
                 this.$refs.pin_3.select()
             }
         }
     },
     methods: {
         pin_focus: function (ref) {
             this.$refs[ref].focus()
             this.$refs[ref].select()
         },
         is_valid_pin_value: function (e, pin_N) {
             const char = String.fromCharCode(e.keyCode)
             const is_value_selected = this[pin_N] !== null && this.$refs[pin_N].selectionStart === 0 && this.$refs[pin_N].selectionEnd === this[pin_N].toString().length
             if ((this[pin_N] === null || this[pin_N].toString().length === 0 || is_value_selected) && parseInt(char, 10) >= 0 && parseInt(char, 10) <= 9) {
                 return true
             }
         e.preventDefault()     } }
 }

What it does:

The data contains properties required for binding the current values of the pin between the template and the controller.

A computed property pin is kept up2date using changes done to any data variable.

We’re using keyup.left, keyup.right and keypress events to switch between each input of the PIN.

Each time the pin computed variable is changed, we $emit an event. See my previous post for learning how to implement Observer Pattern in Vue.

Integrating the PIN Component in our app is as easy as:

<InputPIN />

this.$bus.$on('PIN/change', function (value) {
    console.log('the pin:', value)
})

That’s all. Our Vue PIN Input component is ready.