How To Set Timer Idle In Vue

December 7, 2019 (5y ago)

Do you need to check for inactivity of the user in your Vue apps? If the user is inactive in a period of time, then you wanna to automatically logout the user or show a timer first. Normally, system with confidential data likes bank normally implement this kind of feature.

Goals

To have a Vue apps that listen for inactivity for 3 seconds and show a modal with a 10 second timer. If there is no action during the 10 seconds session, automatically logout the user.

Requirement

Instructions

Assume you have Vue apps running in your local with vex right now. Let’s install the idle-vue package first by running

npm install idle-vue

Then, let’s add our library into main.js file. For now, we will set 3 second for idle time. This is for testing purpose. I added store as a parameter in IdleVue because we want to access the state of idle. Thanks to this library.

Main.js

    import IdleVue from "idle-vue";
 
    const eventsHub = new Vue();
 
    Vue.use(IdleVue, {
      eventEmitter: eventsHub,
      store,
      idleTime: 3000 // 3 seconds,
      startAtIdle: false
    });

This idle-vue have done a great job dealing with listening to inactive event. We can take advantage for vuex, to get the data of status idle in state management.

Basic

Let’s start with basic functionality. So, in your App.vue file add a computed property called IsIdle that return this.$store.state.idleVue.isIdle. It’s a state from the idle-vue package. It will return boolean data.

If you’re not defined store in your IdleVue parameter, the value will be undefined.

App.vue

    <template>
      <div id="app">
        <p>Is it Idle? - {{ isIdle }}</p>
      </div>
    </template>
 
    <script>
    export default {
      computed: {
        isIdle() {
          return this.$store.state.idleVue.isIdle;
        },
      },
    };
    </script>

If we didn’t active for 3 seconds, it stated false

_vue-idle-false

If we’re moving cursor or do any activity, it will stated `yes

Vue Idle True

It shows that Idle-Vue plugins work well in our Vue apps.

Lets add some modal

Let’s create a design for modal. In this example, I’m using TailwindCSS. I added this modal element in separate component.

/src/components/ModalIdle.vue

ModalIdle.vue

    <template>
      <div class="overlay">
        <div class="modal">
          <div class="modal__title">
            <span>Session Expired</span>
          </div>
          <div class="p-3">
            <p>You have left this browser idle for 10 minutes.</p>
            <p>10 second left</p>
          </div>
        </div>
      </div>
    </template>
 
    <style lang="postcss" scoped>
    .overlay {
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      background-color: rgba(0, 0, 0, 0.3);
      z-index: 100;
      display: flex;
      align-items: center;
      justify-content: center;
    }
 
    .modal {
      width: 500px;
      box-shadow: 1px 2px 4px rgba(153, 155, 168, 0.12);
      border-radius: 4px;
      @apply bg-white p-2;
    }
 
    .modal__title {
      color: #38404f;
      @apply flex items-center justify-between p-3 font-bold;
    }
    </style>

_modal

Cool. Let’s import this modal into our App.vue file and add it into our template. The component will be shown if the isIdle is true.

App.vue

    <template>
      <div id="app">
        <ModalIdle v-if="isIdle" />
        <router-view />
      </div>
    </template>
 
    <script>
    import ModalIdle from "@/components/ModalIdle;
    export default {
    	components: {
    		ModalIdle
    	},
    	computed: {
    		isIdle() {
          	return this.$store.state.idleVue.isIdle;
      	}
    	}
    };
    </script>

Congratulation. Now we have a modal if the user is idle. Next, we’re going to create a timer in the modal.

Timer in the modal

What we’re going to do is to add a 10 seconds window for user to take an action before we’re going to remove the user session or logout.

First of all lets create a time variable in our ModalIdle.vue file. This variable will be shown in the modal. We will be used in millisecond format. Let’s add second in computed property to display the time in second format.

ModalIdle.vue

    <template>
      <div class="overlay">
        <div class="modal">
          <div class="modal__title">
            <span>Session Expired</span>
          </div>
          <div class="p-3">
            <p>You have left this browser idle for 3 second.</p>
            <p>{{ second }} second left</p>
          </div>
        </div>
      </div>
    </template>
 
    <script>
    export default {
      data() {
        return {
          time: 10000,
        };
      },
      computed: {
        second() {
          return this.time / 1000;
        },
      },
    };
    </script>

Then, we need to make the time is ticking in the modal like a timer. For to achieve this kind of approach, we need to use setInterval to modify the time variable. Since, we’re using the setInterval, then we need to use clearInterval to kill the the timer.

This is how it should looks like in our component.

ModalIdle.vue

    <template>
      <div class="overlay">
        <div class="modal">
          <div class="modal__title">
            <span>Session Expired</span>
          </div>
          <div class="p-3">
            <p>You have left this browser idle for 10 minutes.</p>
            <p>{{ time }} second left</p>
          </div>
        </div>
      </div>
    </template>
 
    <script>
    export default {
      data() {
        return {
          time: 10000,
        };
      },
      created() {
        let timerId = setInterval(() => {
          this.time -= 1000;
          if (!this.$store.state.idleVue.isIdle) clearInterval(timerId);
 
          if (this.time < 1) {
            clearInterval(timerId);
            // Your logout function should be over here
            alert("logout user....");
          }
        }, 1000);
      },
    };
    </script>

Let me explain what’s going on in the component.

We set a setInterval function to subtract the time variable by 1000 every 1 second.

    let timerId = setInterval(() => {
    		this.time -= 1000;
          ...
        }, 1000);

If the user is coming back to active state from idle, we need to stop the setInterval method from running in the background by using clearInterval method.

    let timerId = setInterval(() => {
          this.time -= 1000;
          if (!this.$store.state.idleVue.isIdle) clearInterval(timerId);
    		...
          }
        }, 1000);

If there is no action from user in 10 seconds, we need to kill the interval and redirect the user to sign out the user and redirect to the login page

    let timerId = setInterval(() => {
      this.time -= 1000;
      if (!this.$store.state.idleVue.isIdle) clearInterval(timerId);
 
      if (this.time < 1) {
        clearInterval(timerId);
        // Your logout function should be over here
        alert("logout user....");
      }
    }, 1000);

_final-design

Source Code

App.vue

    <template>
      <div class="max-w-2xl mx-auto py-16">
        <p>Is it Idle? - <span class="font-bold">{{isIdle}}</span></p>
        <ModalIdle v-if="isIdle"/>
    </div>
    </template>
 
    <script>
    import ModalIdle from "@/components/ModalIdle;
    export default {
    	components: {
    		ModalIdle
    	},
    	computed: {
    		isIdle() {
          	return this.$store.state.idleVue.isIdle;
      	}
    	}
    };
    </script>

ModalIdle.vue

    <template>
      <div
        class="overlay"
      >
        <div class="modal">
          <div class="modal__title">
            <span>Session Expired</span>
          </div>
          <div class="p-3">
        		<p>You have left this browser idle for 10 minutes.</p>
        		<p>{{ time }} second left</p>
          </div>
        </div>
      </div>
    </template>
 
    <script>
    export default {
    	data() {
    		return {
    			time: 10000
    		}
    	},
    	created() {
        let timerId = setInterval(() => {
          this.time -= 1000;
          if (!this.$store.state.idleVue.isIdle) clearInterval(timerId);
 
          if (this.time < 1) {
            clearInterval(timerId);
            // Your logout function should be over here
            alert('logout user....');
          }
        }, 1000);
      }
    };
    </script>

You can view the source code in my github - Source Code

Thanks for reading my article. Let me know if you have any idea, what should I write on my next article.