Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I properly update Vuex state from my Vuetify data-table

I am using Vue, Vuex, and Vuetify to display courses in data-table and want in-line editing as a feature. Please see relevant component code below.

#Courses.vue

<template>
  <v-data-table 
  :headers="headers"
  :items="courses"
  :search="search"
  :loading="loading"
  no-data-text="No Courses Available"
  >

    <template slot="items" slot-scope="props">
      <tr>
        <td>
          <v-edit-dialog
          :return-value.sync="props.item.title"
          lazy
          >
            {{ props.item.title }}
            <v-text-field
            slot="input"
            label="Enter New Course Title"
            v-model="props.item.title"
            single-line
            counter
            @keyup.enter="onUpdateCourse({ id: props.item.id, title: props.item.title})"
            ></v-text-field>
          </v-edit-dialog>
        </td>

        <td>{{ props.item.category }}</td>
        <td>{{ props.item.startDate | date }}</td>
        <td>{{ props.item.endDate | date }}</td>
        <td>{{ props.item.location }}</td>
      </tr>
    </template>
  </v-data-table>
</template>

<script>
  export default {
    data() {
      return {
        headers: [** table headings **],
      };
    },
    computed: {
      courses() {
        return this.$store.getters.courses;
      },
    },
    methods: {
      onUpdateCourse(itemToUpdate) {
        debugger;
        this.$store.dispatch('updateCourse', itemToUpdate);
      },
    },
  };
</script>

It works; but I take issue with the fact that this approach alters the Vuex state directly: the only reason to dispatch(‘updateCourse’, itemToUpdate) is to update the db (firestore in this case). I would have thought it preferable to update the $store.state solely via the Vuex actions/mutations rather than have it syncing directly here.

So, my first question is: Should I take issue with this, and if not why not?

Because it was bugging me, I added a local copy of the Vuex courses array to the computed section:

localCopy() {
  return this.courses.map(x => Object.assign({}, x));
},

and built the data-table using :items="localCopy". This allows me to update the courses from within the Vuex actions but the data table doesn’t update until I click somewhere else in the app.

So, my second question is: If this is the correct approach, how do I keep the reactivity of the component?

Thanks for any help.

(PS – When cutting and pasting code, or editing in the text box, it seems that some of the double quotes " are unfortunately getting converted to fancy quotes . It is doubly unfortunate that I am dyslexic and although I have done my best to hunt them down, I literally can’t see them most of the time. Please don’t hate on me)

like image 766
Adam Avatar asked Mar 24 '18 15:03

Adam


People also ask

How do I change my Vuex state?

Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations.

Which part of Vuex is responsible for directly making changes to the data store?

The second key defined in the store is the mutations key. As the name suggests, it contain an object of all of the properties responsible for making changes to the state .

What is the use of Mapstate in Vuex?

Mapping in Vuex enables you to bind any of the state's properties, like getters, mutations, actions, or state, to a computed property in a component and use data directly from the state. Although we can get the job done with this. $store.state.user.data.name , we can use a map helper to simplify it to this.


1 Answers

To not assign changes to props.item.title, do:

  • Remove the .sync in <v-edit-dialog :return-value="props.item.title".
  • Replace v-model with :value in <v-text-field :value="props.item.title".

As .sync has an implicit @return-value:update="props.item.title = $event" and v-model has an implicit @input="props.item.title = $event (roughly), the above alone (removing .sync and replacing v-model with :value) would stop title from being directly modified.

To make it being modified via dispatch also add an @input listener that calls the dispatch: @input="onUpdateCourse({ id: props.item.id, title: props.item.title})".

Finally, here's how your code should look like:

<td>
  <v-edit-dialog
  :return-value="props.item.title"
  lazy
  >
    {{ props.item.title }}
    <v-text-field
    slot="input"
    label="Enter New Course Title"
    :value="props.item.title"
    @input="onUpdateCourse({ id: props.item.id, title: props.item.title})"
    single-line
    counter
    @keyup.enter="onUpdateCourse({ id: props.item.id, title: props.item.title})"
    ></v-text-field>
  </v-edit-dialog>
</td>
like image 140
acdcjunior Avatar answered Oct 22 '22 09:10

acdcjunior