0
votes

I'm working on a Nuxt.js application using Vuetify and Nuxt. One of my pages displays a table showing a list of games you can possibly join. My goal is to keep updating this table automatically whenever games are added to or deleted from the list.

So in my store I set up the following state and mutations:

export const state = () => ({
  games: {}
})

export const mutations = {
  addGame(state, game) {
    state.games[game.id] = game
  },
  removeGame(state, id) {
    delete state.games[id]
  }
}

as well as this getter that transforms the games object into a list, in order to make it usable by my component:

export const getters = {
  games(state) {
    const games = []
    for (const key in state.games) {
      games.push(state.games[key])
    }
    return games
  }
}

Now here we have the relevant parts of my component:

<template>
  <v-data-table
    :headers="headers"
    :items="getGames()"
    class="elevation-1"
  >
    <template v-slot:items="props">
      <td>{{ props.item.name }}</td>
      <td class="text-xs-center">
        {{ props.item.players.length }}/{{ props.item.numberOfPlayers }}
      </td>
      <v-btn :disabled="props.item.nonJoinable" class="v-btn--left" @click="joinGame(props.item.id)">
        {{ props.item.nonJoinable ? 'Already joined': 'Join' }}
      </v-btn>
    </template>
  </v-data-table>
</template>

<script>
export default {
  data() {
    return {
      games: [],
      headers: [
        {
          text: 'Game name',
          align: 'left',
          sortable: true,
          value: 'name'
        },
        {
          text: 'Players',
          align: 'center',
          sortable: true,
          value: 'players'
        }
      ]
    }
  },
  async fetch({ store, params }) {
    await store.dispatch('fetchGamesList')
  },
  methods: {
    joinGame(id) {
      this.$store.dispatch('joinGame', id)
    },
    getGames() {
      console.log(this.$store.getters.games)
      this.games = this.$store.getters.games
    }
  }
}
</script>

I've tried this configuration as well as declaring "games" as a computed property or declaring a "watch" method. In none of this cases I could see the table automatically update whenever any of the mutations above is triggered (the data on the store are updated correctly).

What would it be the correct way to get the desired behavior out of my component?

1
it should work, can u create a codesanbox or fiddle to demonstrate problem?Aldarund
Can you show your actions from the store? getGames should be a computed property to reflect changes in the store, but it is up to your actions to commit the mutations correctly.Andrew1325
@Aldarund I'm trying with codesandbox but I can't get the vuex store working (Cannot read property 'dispatch' of undefined ). I'll try again or maybe I'll find another way to share the code.Adriano Todaro
@Andrew1325 The mutations I show here are not triggered by an action but by a Vuex plugin that I wrote. This plugin uses a websocket to receive notifications from the back-end whenever a game is added or removed and simply does: store.commit('addGame', data.game_added) and store.commit('removeGame', data.game_removed). As far as I can see the mutations are invoked correctly and the state changes accordingly. In fact, when the page is reloaded the table correctly displays the updated list of games. The only problem is that it doesn't do it reactively (without refreshing).Adriano Todaro

1 Answers

2
votes

As I said in my comment, you should use a computed property for getGames but you could use mapGetters in there. So if your store is being updated then this should work:

//your component
<template>
  <v-data-table
    :headers="headers"
    :items="games"
    class="elevation-1"
  >
    ... //rest of the template code
  </v-data-table>
</template>
<script>
import {mapGetters} from 'vuex'
export default {
  data() {
    return {
      headers: [
        // your headers objects
      ]
    }
  },
  computed: {
    ...mapGetters({
      games
    }),
  },
  ... //rest of scripts but without getGames method
</script>

So delete your getGames method and keep the rest, should work fine.