Search code examples
vue.jsemitquasar

Trigger/update data change from child component to parent component in Quasar/Vue incase of child component has list of items


I am using Quasar to develop my app and still learning. I have a parent component that has 4 child components as shown in the image (https://i.sstatic.net/KNiCU.jpg).

I can $emit child component comp1,2,3 changes to parent component, but I am not sure how I can $emit' change from child comp 4 to parent. Reason being comp4 receive list(please see list of data in comp4) of data asprops``` from the parent.

I have the following code sample for comp4: durationOptions coming as props via Vuex store. I am getting error at line @click="option.selected = !option.selected" because of direct Vuex store update.

<q-list bordered separator dense no-padding>
    <q-item-label header>Setup duration option and fee</q-item-label>
    <div class="row">
      <q-item-label class="col" dense caption></q-item-label>
      <q-item-label class="col" dense caption>Duration(Hr)</q-item-label>
      <q-item-label class="col" dense caption>Fee($)</q-item-label>
      <q-item-label class="col" dense caption>Discount(%)</q-item-label>
    </div>
    <q-separator spaced />
    <q-item
      clickable
      v-ripple
      v-for="(option, key) in durationOptions"
      :key="key"
    >
      <q-item-section>
        <q-checkbox
          dense
          @click="option.selected = !option.selected"
          v-model="option.selected"
        />
      </q-item-section>
      <q-item-section>
        <q-item-label dense>{{ option.selected }}</q-item-label>
      </q-item-section>

Issue is on click on CHECKBOX, I get error [vuex] do not mutate vuex store state outside mutation. I understand that I should not update Vuex store directly. Or, do I need to update each time Vuex store as and when used clicks on CHECKBOXes? I prefer updating Vuex store on submit/save. Until the submit, how can I have local/temp data change? How can I @emit changes from comp4 to parent? Any help me much appreciated.


Solution

  • You can preserve the state on parent and later send everything to the store like this:

    Parent.vue

    <template>
    <child :options="options" @option-toggle="onOptionToggle" />
    </template>
    <script>
      data() {
          return {
            options: {
              foo: {
                title: 'foo',
                isSelected: false
              },
              bar: {
                title: 'bar',
                isSelected: false
              }
            }
          },
          methods: {
            onOptionToggle(key, isSelected) {
              this.$set(this.options[key], 'isSelected', isSelected)
            }
          }
    </script>
    

    Child.vue

    <template>
    <div v-for="(value, key) in options" @click="toggleOption(value, key)"> {{value.title}}</div>
    </template>
    <script>
      methods: {
        toggleOption(value, key) {
          this.$emit('option-toggle', key, !value.isSelected);
        }
      }
    </script>