Managing State for Overlay Dismissed Components in Vuetify
Asked Answered
L

2

7

I'm building out a vuetify/nuxt frontend for the first time, and I've moved my v-navigation-drawer component out of the default.vue layout, and into it's own component, so that it can be reused in multiple layouts.

The activator for this drawer still remains in the default.vue component, so I added a sidebar state to vuex:

export const state = () => ({
    baseurl: 'http://example.com/api/',
    sidebar: false,
    authenticated: false,
    token: null,
    user: null,
})

The mutator for the sidebar looks like so:

export const mutations = {
    toggleSidebar(state) {
        state.sidebar = !state.sidebar;
    }
}

This works perfectly when opening the drawer, but because the drawer is dismissed via clicking the overlay, or clicking off of sidebar (if you've turned the overlay off) vuex throws a huge error:

enter image description here

How can I make this work correctly through vuex?

Lindane answered 22/11, 2017 at 19:36 Comment(0)
J
29

Instead of binding the drawer's model directly to $store.state.sidebar, use a computed setter in the drawer component. Note that you must pass in the new value from the drawer itself, don't just toggle whatever's already in the store.

<template>
  <v-navigation-drawer v-model="drawer" ...>
</template>

<script>
  export default {
    computed: {
      drawer: {
        get () {
          return this.$store.state.sidebar
        },
        set (val) {
          this.$store.commit('sidebar', val)
        }
      }
    }
  }
</script>
// vuex mutation
sidebar (state, val) {
  state.sidebar = val
}

https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter
https://vuex.vuejs.org/en/forms.html

Another option is to bind the prop and event separately

<template>
  <v-navigation-drawer :value="$store.state.sidebar" @input="$store.commit('sidebar', $event)" ...>
</template>

https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components

Jamima answered 23/11, 2017 at 7:53 Comment(4)
You are a flippin genius my friend! To my credit I was VERY close to this ... I just wasn't passing the value into the mutation. But finally after trying everything under the sun .... bingo! Thanks a ton.Lindane
You are genius. This is what i have looking for. Thanks!Tomikotomkiel
Excellent! The missing guide to Vuetify v-navigation-drawer ! There are open issues on Vuetify about this.... And the answer - for most cases - is yours!Paucker
This is the answer to so many unanswered posts. Can anyone explain where val comes from and how it is set? Is it just a default that is generated with v-model?Brooklet
W
0

Another solution is to use vuex-map-fields package which enables two-way data binding for states saved in a Vuex store.

It makes the code clear, readable more than the normal way (as in the accepted answer).

Basic example:

in your store file


// Import the `getField` getter and the `updateField`
// mutation function from the `vuex-map-fields` module.
import { getField, updateField } from 'vuex-map-fields';

export const state = () => ({
    baseurl: 'http://example.com/api/',
    sidebar: false,
    authenticated: false,
    token: null,
    user: null,
})

export const getters = {
   // Add the `getField` getter to the
   // `getters` of your Vuex store instance.
   getField,
}

export const mutations = {
   // Add the `updateField` mutation to the
   // `mutations` of your Vuex store instance.
   updateField,
}

in your component

template>
  <v-navigation-drawer v-model="sidebar" ...>
</template>

<script>
import { mapFields } from 'vuex-map-fields';

export default {
  computed: {
    // The `mapFields` function takes an array of
    // field names and generates corresponding
    // computed properties with getter and setter
    // functions for accessing the Vuex store.
    ...mapFields([
      'baseurl',
      'sidebar',
      // etc...
    ]),
    }
  }
</script>

for more details, you can check its githab page

Wealthy answered 25/3, 2021 at 7:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.