Vue.js: Dynamically display buttons in the navigation bar depending on the user's login status through Vuex Store state

I am currently in the process of creating a navigation bar that displays different buttons based on whether the user is logged in or not. To achieve this, I am utilizing Vuex and localStorage to manage the state.

My goal is to develop a dynamic menu using a list of objects (referred to as rightMenu) which includes information about each button such as route, title, and a flag indicating whether the button should be displayed when the user is logged in.

After a user logs into the system, the

this.$store.state.auth.isUserLoggedIn
changes to true. However, the template does not update accordingly, resulting in the buttons remaining in their initial state from when the user was not logged in. For instance, the 'sign out' button doesn't appear even after the
this.$store.state.auth.isUserLoggedIn
updates. Only upon manually reloading the page with 'ctrl+F5', do the buttons display correctly.

In order to tackle this issue, I am considering forcing a page reload whenever a user logs in or out, although I realize this may not be the best solution.

Is there anyone who could offer assistance?

Below is the code snippet that I am currently working with:

Menu.vue > template

<div>
    <v-toolbar color='grey darken-3' dark>
        <v-toolbar-title>Site</v-toolbar-title>

        ...

        <v-toolbar-items class='hidden-sm-and-down'>
            <v-btn v-for='item in rightMenu' :key='item.title'
                   :to='item.to' v-if='item.showButton' flat>
                   {{ item.title }}
            </v-btn>
        </v-toolbar-items>

    </v-toolbar>

    <router-view/>
</div>

Menu.vue > script

export default {
  data () {
    return {
      rightMenu: [
        { to: '/sign_in', title: 'sign in'
          showButton: !this.$store.state.auth.isUserLoggedIn },
        { to: '/sign_up', title: 'sign up'
          showButton: !this.$store.state.auth.isUserLoggedIn },
        { to: '/sign_out', title: 'sign out'
          showButton: this.$store.state.auth.isUserLoggedIn }
      ]
    }
  },
  ...
}

store.js

const store = new Vuex.Store({
  state: {
    auth: {
      token: '',
      isUserLoggedIn: false
    }
  },
  mutations: {
    setAuthToken (state, token) {  
      state.auth.token = token
      state.auth.isUserLoggedIn = !!token
      localStorage.setItem('store', JSON.stringify(state))
    },
    cleanAuth (state) {  
      state.auth = {
        token: '',
        isUserLoggedIn: false
      }
      localStorage.setItem('store', JSON.stringify(state))
    }
  }
  ...
})

EDIT 1:

By directly referencing

this.$store.state.auth.isUserLoggedIn
in my code, the button visibility works as expected. An example is provided below:

Menu.vue > template

<v-toolbar-items class='hidden-sm-and-down'>
    <v-btn v-if='this.$store.state.auth.isUserLoggedIn' flat> 
      Test {{ this.$store.state.auth.isUserLoggedIn }}
    </v-btn>
</v-toolbar-items>

This leads me to believe that the issue lies in the binding between showButton and

this.$store.state.auth.isUserLoggedIn
.

Answer №1

Utilize the computed property in order to create a reactive effect:

<template>
...
<v-btn v-for='item in rightMenu' :key='item.title'
  :to='item.to' v-if='isUserLoggedIn(item.title)' flat>
  {{ item.title }}
</v-btn>
...
</template>

<script>
...
computed: {
  isUserLoggedIn() {
    return (title) => { // no caching benefits will be available
      if (title === 'sign out') {
        return this.$store.state.auth.isUserLoggedIn;
      }
      return !this.$store.state.auth.isUserLoggedIn;
    }
  }
}
...
</script>

Answer №2

Thanks to the valuable insights provided by Chris Li, Andrei Gheorghiu, and Sajib Khan, I was able to successfully resolve my issue.

Andrei Gheorghiu emphasized that accessing computed properties in data() is not possible, while Chris Li suggested using a computed variable instead. By combining their suggestions with an example from Sajib Khan, I was able to devise a solution, which I am sharing below in the hopes that it may benefit others facing a similar challenge.

In essence, I created a computed property that returns an array, ensuring that whenever

this.$store.state.auth.isUserLoggedIn
updates, the array also updates accordingly, thereby affecting the menu as well.

I plan to implement a mapGetter for

this.$store.state.auth.isUserLoggedIn
. Once I have done so, I will update this answer.

Many thanks to all of you for your assistance.

<script>
export default {
  data () {
    return { ... }
  },
  computed: {
    rightMenu () {
      return [
        { title: 'sign_in', to: '/sign_in', 
            showButton: !this.$store.state.auth.isUserLoggedIn },
        { title: 'sign_up', to: '/sign_up', 
            showButton: !this.$store.state.auth.isUserLoggedIn },
        { title: 'sign_out', to: '/sign_out',
            showButton: this.$store.state.auth.isUserLoggedIn }
      ]
    }
  }
}
</script>

EDIT 1: Solution using mapGetters

Menu.vue

<script>
import { mapGetters } from 'vuex'

export default {
  data () {
    return { ... }
  },
  computed: {
    ...mapGetters([
      'isUserLoggedIn'
    ]),
    rightMenu () {
      return [
        { title: 'sign_in', to: '/sign_in', 
            showButton: !this.$store.state.auth.isUserLoggedIn },
        { title: 'sign_up', to: '/sign_up', 
            showButton: !this.$store.state.auth.isUserLoggedIn },
        { title: 'sign_out', to: '/sign_out',
            showButton: this.$store.state.auth.isUserLoggedIn }
      ]
    }
  }
}
</script>

store.js

The following getter has been added:

...
getters: {
  isUserLoggedIn (state) {
    return state.auth.isUserLoggedIn
  }
}
...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using AJAX along with the append method to dynamically add identical HTML content multiple times to a single element

Although I have successfully implemented most of the desired functionality with this JavaScript code, there is a persistent bug that is causing unnecessary duplicates to be created when appending HTML. Detecting Multiples The problem lies in the fact tha ...

In mongoose and nodejs, there is no method called .find()

I am encountering an issue while attempting to locate by id and receiving the error bankApp.find is not a function. Below is my schema: import {model, Schema} from "mongoose"; const StatusResponse = new Schema({ uniqueKey: {type: String, trim: true, ...

Creating a notification for specific choices in a dropdown menu

I am working on a form that includes a select element with multiple options. Depending on the option selected, a different form will be displayed. My concern is if a user starts filling out one form and then decides to select another option, I want to add ...

What causes a React Native wrapped component to re-render consistently?

I have a functional component in React native (expo) that is displaying a page using the stack navigator. On this page, there is a simple color picker (react-native-wheel-color-picker), which is a native component, and a button that updates the state. I&a ...

Using browserify "require" in console: A step-by-step guide

My Rails project now includes the browserify and pinyin packages, thanks to the browserify-rails installation. To find out more about the pinyin package, check out this link: https://github.com/hotoo/pinyin var pinyin = require("pinyin"); console.log(pin ...

Ways to implement a resize function in Angular JS without relying on the document and window objects

Is there a way to convert the following jQuery code into Angular JS without relying on Document and Window? Can we write the code without utilizing Document.ready and window? ...

An error occurs when attempting to assign a value to a MUI file TextField

Struggling with setting the value of a MUI Textfield that has type="file" props, resulting in the following exception being thrown: Uncaught DOMException: An attempt was made to use an object that is not, or is no longer, usable Interest ...

Event listener is failing to trigger when clicked in content script and directed to popup on Google Chrome Extension

I created a button within a popup using jQuery click event in a content script, but it is not working. How can I attach a click event to the button by Element ID? It is worth noting that the jQuery Document Load event is functioning properly. The followin ...

Is it possible to customize the appearance of the selected item in a select box? Can the selected value be displayed differently from the other options?

My current project involves working with the antd' select box. I have been trying to customize the content inside the Option which usually contains regular text by incorporating some JSX into it. The output currently looks like this: https://i.sstati ...

Display a PHP file's content in an iframe without revealing the file path in the source code

In my project built with Laravel, I am utilizing PDF.JS to showcase various PDF documents. To secure the pdf path, I am attempting to conceal it by passing a PHP file in the src field of an iframe. In my view: <iframe id="reader" src="http://server.de ...

The Magic of Javascript Routing with Regex Implementation

I'm currently developing a Javascript Router similar to Backbone, Sammy, and Spin. However, my specific requirements are rather straightforward. I need the ability to define a series of routes along with their corresponding callbacks, and I want to be ...

Trouble with mobile compatibility for .json file content population in HTML elements script

Check out THIS amazing page where I have a series of placeholders for phone numbers in the format: 07xxxxxxxx. By simply clicking the green button "VEZI TELEFON", each placeholder in the green boxes gets replaced with a real phone number from a JSON file u ...

Safari experiencing CORS violation while Chrome is unaffected

I'm encountering an issue with my React web app that communicates with an Express web server. While everything functions correctly in Chrome, I'm facing an error when accessing the app in Safari: XMLHttpRequest cannot load https://subdomain.exam ...

Exploring the Potential of Mobile Development using AngularJS

I am in the process of creating an app with the following key design objectives: Efficiency and modularity - a light core that can be expanded to create a feature-rich app in a cohesive manner Mobile focus - this app is primarily aimed at mobile platform ...

Scrolling up or down in an HTML webpage using a script

Seeking a code snippet for my website that will allow me to achieve the following functionality: Upon clicking on text_head1, a list of lines should scroll down. Subsequently, when I click on text_head2, the previous list should scroll up while the new l ...

Utilizing Angular 2+ to effectively manipulate the HTML Document Object Model with JavaScript in order to execute scripts

I'm facing an issue with inserting a script into my Angular project that has a specific format. <script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-events.js"> { "width": "510", "height": "600", "impo ...

What is the best way to use AJAX to navigate to a different webpage while sending data along with

After successfully saving a form and receiving a success message, I am able to redirect to another page using window.location.href = '/home'; with no issues. However, I would like to pass the success message to the home page after the redirect. W ...

Is it advisable to use the return statement immediately following res.render in app.js?

An error popped up indicating that Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client at ServerResponse.setHeader (_http_outgoing.js:470:11). My solution was to add a return statement after every use of res.render or ...

Error Message: The function "menu" is not a valid function

I've encountered an issue with a function not being called properly. The error message states "TypeError: menu is not a function." I attempted to troubleshoot by moving the function before the HTML that calls it, but unfortunately, this did not resolv ...

Extract data from a JSON file and refine an array

Currently, I am working with reactjs and have an array stored in a json file. My current task involves filtering this array using the selectYear function. However, when attempting to filter the data using date.filter, I encounter the following error: An ...