1

I'm generating some menu buttons dynamically (not sure if that's best practice)

script

items: [
{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/' },
{ title: 'Register', icon: 'mdi-image', route: '/register' },
{ title: 'Login', icon: 'mdi-help-box', route: '/login' },
],

html

<v-list-item v-for="(item, i) in items" :key="i" link :to="{path: item.route}">

But what I want to do is hide the dashboard button until they have signed in. The user signed in value is kept in store.

$store.state.user.signedIn // true/false

How can I programmatically hide buttons depending on signed in value? I was trying to do this

{ title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', reqAuth: true }

But not sure how to get it working smoothly in the html. I'd also like to do the reverse later on the login/register buttons, if the user IS signed in then these should hide and a Logout button will come into play.

2 Answers 2

2

You have two options:

  • A) have separate menu arrays and display one or the other based on isLoggedIn. If you have any items showing in both cases, you'll need to place them in a third array and concat one of the first two with the third
  • B) have a boolean property on each menu item stating whether it should show when isLoggedIn or not. If you have menu items showing on both, you'll need either two props on each item (showWhenLoggedIn, showWhenLoggedOut - change them if too long) or, alternatively, you could make the show an array of booleans: show: [true, false] - first bool controlling whether it's shown when logged out, second when logged in).

Solution A) example (separate arrays):

Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  data: () => ({
    loggedInMenuItems: [
      { title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', show: [false, true] },
    ],
    loggedOutMenuItems: [
      { title: 'Register', icon: 'mdi-image', route: '/register', show: [true, false] },
      { title: 'Login', icon: 'mdi-help-box', route: '/login', show: [true, false] },
    ],
    permanentMenuItems: [
      { title: 'Terms and Conditions', icon: 'mdi-whatever', route: '/terms', show: [true, true] }
    ],
    isLoggedIn: false
  }),
  computed: {
    menuItems() {
      return (this.isLoggedIn
        ? this.loggedInMenuItems
        : this.loggedOutMenuItems
      ).concat(this.permanentMenuItems)
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <label><input v-model="isLoggedIn" type="checkbox"> Is logged in</label>
  <pre v-html="menuItems.map(m => m.title)"></pre>
</div>

Solution B) example:

Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
  el: '#app',
  data: () => ({
    items: [
      { title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', show: [false, true] },
      { title: 'Register', icon: 'mdi-image', route: '/register', show: [true, false] },
      { title: 'Login', icon: 'mdi-help-box', route: '/login', show: [true, false] },
      { title: 'Terms and Conditions', icon: 'mdi-whatever', route: '/terms', show: [true, true] }
    ],
    isLoggedIn: false
  }),
  computed: {
    menuItems() {
      return this.items.filter(item => item.show[Number(!!this.isLoggedIn)])
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <label><input v-model="isLoggedIn" type="checkbox"> Is logged in</label>
  <pre v-html="menuItems.map(m => m.title)"></pre>
</div>

I personally prefer the second one, for brevity. I also find it a tad more elegant.

However, in large teams or in projects where code complexity needs to be kept to a minimum and code readability to a maximum, the first solution is often times preferred.

Lastly, second solution allows more flexibility for menu items order, although it's not a real issue (implementing an order attribute to each item would be trivial).


Note: obviously, isLoggedIn should come from state, not from component data fn. I placed it in data so you could easily test it here.

Sign up to request clarification or add additional context in comments.

Comments

1

Your items property should be defined as computed property and add shown field in each item of items and use state value as its value in dashboard link :

computed :{
 items(){
const signedIn=$store.state.user.signedIn; 
  return  [
      { title: 'Dashboard', icon: 'mdi-view-dashboard', route: '/', shown:signedIn },
      { title: 'Register', icon: 'mdi-image', route: '/register',shown:!signedIn},
      { title: 'Login', icon: 'mdi-help-box', route: '/login' , shown:!signedIn},
]
  }
}

in template add

<v-list-item v-for="(item, i) in items" :key="i" link v-if="item.shown" :to="{path: item.route}">

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.