0

Use Case: I have a component that contains a datatable, that lists Applications, I click a row and it opens a component with the fields loaded appropriately (new or edit).

The Problem: a component loads a ** reference ** of the data, new or existing, that I can bind to in a component. Because it is not a copy, I cannot edit it.

Quick explanation on the code: New() calls Open(), both load the Component ViewApplication.

Datatable Component

<template>
  <div id="inspire" data-app>
      <v-card>
        <v-banner single-line>
              <v-btn @click="New">New</v-btn>
        </v-banner>
        <v-card>
          <v-layout>
            <v-list-item>
              <v-list-item-content>
                <v-row>
                  <v-col>
                    <v-data-table
                      :items="items"
                      return-object
                      @click:row="Open"
                    >
                      <template #top>
                        <v-dialog v-model="dialog" max-width="600">
                          <ViewApplication
                            :loadedapp="loaded"
                            @reload="Load"
                            @close="close"
                          />

                        </v-dialog>
                      </template>
                    </v-data-table>
                  </v-col>
                </v-row>
              </v-list-item-content>
            </v-list-item>
          </v-layout>
        </v-card>
      </v-card>
  </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex'
export default {
  data: () => ({
    dialog: false,
    items: this.LoadApplications(),
  }),
  computed: {
    ...mapGetters({
      applications: 'modules/Manage/getApplications',
    }),
  },
  methods: {
    ...mapActions({ LoadApplications: 'modules/Manage/LoadApplication' }),
    Open(item) {
      console.log('Open item: ' + item)
      this.loaded = item
      this.$store.commit('modules/Manage/setApplication', item)
      this.dialog = true
    },
    New() {
      let item = { app_name: '', roles: `[]`, api: '' }
      this.Open(item)
    },

  },
}
</script>

ViewApplication Component

<template>
  <v-card v-if="loadedapp">
    <v-col>
      <v-text-field v-model="app_name" dense label="Application Name" />
      <v-row>
        <v-col col="6">
          <v-text-field
            v-model="role"
            label="Role"
            :append-outer-icon="'mdi-send'"
            @click:append-outer="roles.push(role)"
          />
        </v-col>
        <v-col col="6">
          <v-select
            v-model="roles"
            :items="roles"
            :menu-props="{ maxHeight: '400' }"
            label="Roles"
            multiple
          ></v-select>
        </v-col>
      </v-row>

      <v-text-field v-model="api" dense label="API" />
    </v-col>
    <v-card-actions>Save, Delete</v-card-actions>
  </v-card>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  props: {
    loadedapp: {
      type: Object,
      default: () => {
        return { app_name: '', roles: `[]`, api: '' }
      },
    },
  },
  data() {
    return {
      localapp1: this.getApp,
      localapp2: { ...this.getApp },
      localapp3: this.loadedapp,
      localapp4: { ...this.loadedapp },
      role: '',
      app_name: '',
      roles: [],
      api: '',
    }
  },
  computed: {
    ...mapGetters({
      path: 'modules/Auth/gutCustomerURL',
      getApp: 'modules/Manage/getApp',
    }),
  },
}
</script>

DevTools

bruno mac
  • 23
  • 7
  • If you want to have something dynamic coming from your Vuex, you could indeed use a combo of `computed` + `mapState` and toggle your things accordingly. If something is not working, we may start debugging there but a `ternary` depending on those should be totally fine. What do you see in your devtools? – kissu Oct 29 '21 at 17:58
  • Also, maybe try to narrow down and keep only the essential stuff, your snippets are quite long and hard to focus on IMO. I've edited it with some proper syntax highlight already. – kissu Oct 29 '21 at 18:00
  • The DevTools show both the Store and the Prop changing appropriately, just don't know how to copy it into into the local component data. – bruno mac Oct 29 '21 at 18:29
  • Why do you even want to copy it? Just use the value directly for the read and for the edit, update it after a clone deep. – kissu Oct 29 '21 at 21:29
  • v-model="getApp.app_name" produces "Error: [vuex] do not mutate vuex store state outside mutation handlers." The prop produces a lint error: Unexpected mutation of "loadedapp" prop. – bruno mac Nov 01 '21 at 13:59
  • You can look for this error on SO itself: https://stackoverflow.com/a/66933350/8816585 Make a deepClone of your object before mutating it. – kissu Nov 01 '21 at 17:04

1 Answers1

-1

Found these links instructive: https://vuex.vuejs.org/guide/forms.html https://markus.oberlehner.net/blog/form-fields-two-way-data-binding-and-vuex/

Actual solution:

  props: {
    loadedapp: {
      type: Object,
      default: () => {
        return { app_name: '', roles: `[]`, api: '' }
      },
    },
  },
  data() {
    return {
      role: '',
      app_name: '',
      roles: [],
      api: '',
    }
  },
  watch: {
    loadedapp: {
      immediate: true,
      handler() {
        this.init()
      },
    },
  },
  methods: {
    init() {
      if (this.loadedapp) {
        this.app_name = this.loadedapp.app_name
        this.roles = JSON.parse(this.loadedapp.roles)
        this.api = this.loadedapp.api
      }
    },}
bruno mac
  • 23
  • 7