Skip to content
Advertisement

How to watch if a token gets registered in localStorage and change the value of a binded property accordingly?

Currently, whenever a user logs in using correct credentials, a token get saved in the local storage. Now I’m trying to hide signin and signup after the user logs in.

The code I currently have works relatively alright, however, I noticed that when the user logs in, the signin and signup routes do not disappear until the page is refreshed which is not very SPA like.

Why is this happening?

<template>
    <div class="nav-header">
        <div class="wrapper">
            <ul class='nav-ul'>
                <router-link to="/" tag='li' active-class='active' exact><li><a>Home</a></li></router-link>
                <router-link to="/signup" v-if="!isLoggedIn" tag='li' active-class='active' exact><li><a>Sign Up</a></li></router-link>
                <router-link to="/signin" v-if="!isLoggedIn" tag='li' active-class='active' exact><li><a>Sign In</a></li></router-link>
            </ul>
        </div>
    </div>
</template>

<script>
    export default {
        computed: {
            isLoggedIn() {
                return !!window.localStorage.getItem('token')
            }
        }
    }
</script>

App.vue

<template>
    <div id="app">
        <app-header></app-header>
        <router-view></router-view>
    </div>
</template>

<script>
    import Header from './components/header.vue';
    export default {
        components: {
            appHeader: Header
        }
    }
</script>

Sigin.vue

<template>
    <div>
        <input v-model="email" placeholder="Your Email...">
        <input v-model="password" placeholder="Your Password...">
        <button v-on:click.prevent="signin" type="submit" name="submit">Submit</button>
    </div>
</template>

<script>
    import axios from 'axios'
    axios.defaults.baseURL = 'http://94.155.24.68/api';

    export default {
        data: function() {
            return {
                email: '',
                password: ''
            }
        },
        methods: {
            signin: function(){
                axios.post('/signin', {
                    email: this.email,
                    password: this.password
                })
                .then((response) => {
                    console.log(response);
                    const token = response.data.token;
                    localStorage.setItem('token', token);
                }).catch((error) => console.log(error));
            }
        }
    }
</script>

Answer

The reason this doesn’t work is because you are trying to watch for changes on the non reactive localStorage.

To make it reactive I tend to create a global Vue instance using Vue.prototype (allowing you to use it in all your components)

Vue.prototype.$localStorage = new Vue({
    data: { 
       // token property returning the ls token value 
       token: window.localStorage.getItem('token') 
    },
    watch:{ 
       // watcher listening for changes on the token property
       // to ensure the new value is written back to ls 
       token(value){ window.localStorage.setItem('token', value) } 
    }
})

//  you can now access the token in all your components using
//  this.$localStorage.token            get the token value
//  this.$localStorage.token = 'tkn';   set the token value  

Demo https://codepen.io/jakob-e/pen/LMJEYV?editors=1010

To implement it in your solution you can do:

// in the header component
computed: {
  isLoggedIn(){ return this.$localStorage.token !== ''; }
}

// in the signin component
signin(){
  axios.post('/signin', {
    email: this.email,
    password: this.password
  })
  .then((response) => {
    console.log(response);
    const token = response.data.token;
    this.$localStorage.token = token;  
  })
  .catch((error) => console.log(error));
}
Advertisement