3

I am trying to get the changed value of vuetify v-select by using $emit but it doesn't work. I divided components by applying atomic design pattern (atoms(child component and not to connect with the store), organisms(parent component)) and vuex stores. I think $emit data is OK but anything doesn't work after the process.

This is for a new application for management page with using vue, vuex, vuetify, atomic design connecting to API server.

Components

child component - in atoms folder

<template>
  <v-select
    :items="list"
    :label="label"
    v-model="selected"
    item-value="id"
    item-text="name"
    return-object
    @change="changeSelected"
  ></v-select>
</template>

<script>
export default {
  props: ["list", "label", "defaultSelected"],
  data() {
    return {
      selected: this.defaultSelected
    };
  },
  methods: {
    changeSelected(newValue) {
      console.log(newValue);    // display changed new data
      this.$emit("changeSelected", newValue);
    }
  }
};
</script>

parent component - in organisms folder

<template>
  <v-select-child
    :select-label="label"
    :select-list="list"
    :default-selected="selected"
    @change-selected="changeSelected"    // problem issue?
  >
  </v-select-child>
</template>
<script>
import { mapState } from "vuex";
export default {
  data() {
    ...
  },
  computed: {
    ...mapState({
      list: state => state.list
    })
  },
  methods: {
    changeSelected() {
      console.log("changeSelected");    // doesn't work
      this.$store.dispatch("setSelected", { payload: this.selected });
    }
  }
};
</script>

vuex stores

index.js

export default new Vuex.Store({
  modules: {
    xxx
  },
  state: {
    list: [
      {
        name: "aaaaa",
        id: "001"
      },
      {
        name: "bbbbb",
        id: "002"
      }
    ]
  },
  getters: {},
  mutations: {},
  actions: {}
});

xxx.js

export default {
    selected: { id: "001" }
  },

  getters: {
    //
  },

  mutations: {
    updateSelected(state, payload) {
      console.log("payload");    // doesn't work
      console.log(payload);
      state.selected = payload;
      console.log(state.selected);
    }
  },

  actions: {
    setSelected({ commit }, payload) {
      console.log("Action");    // doesn't work
      commit("updateSelected", payload);
    }
  }
};

It does not print any console log after changeSelected function.

Doyoun
  • 89
  • 1
  • 11

3 Answers3

1

In document

Unlike components and props, event names don’t provide any automatic case transformation. Instead, the name of an emitted event must exactly match the name used to listen to that event.

That means if you emit event like $emit('changeSelected'), then you need to use @changeSelected. @change-selected will not work.

 <v-select-child
    :select-label="label"
    :select-list="list"
    :default-selected="selected"
    @changeSelected="changeSelected" 
  >
</v-select-child>
tony19
  • 125,647
  • 18
  • 229
  • 307
ittus
  • 21,730
  • 5
  • 57
  • 57
  • Thank you very much! However, I have another problem that changed payloads are added inside the others. `payload { payload {payload { id: aaaaa } } }` Is there any ideas use `$event` with vuetify v-select without using vuex store in the child component? I found this article, [http://arm4.hatenablog.com/entry/2018/07/02/162628] but it uses `$store` directly but I would like to use $store in the parent component. – Doyoun May 27 '19 at 14:18
1

I found a solution below:

child component

<template>
  <v-select
    :label="label"
    :items="list"
    v-model="selected"
    item-value="id"
    item-text="name"
    return-object
  ></v-select>
</template>

<script>
export default {
  props: ["list", "label", "defaultSelected"],
  computed: {
    selected: {
      get() {
        return this.defaultSelected;
      },
      set(newVal) {
        if (this.selected !== newVal) {
          this.$emit("changeSelected", newVal);
        }
      }
    }
  }
};
</script>

parent component

<template>
  <v-select-child
   :label="label"
   :list="list"
   :defaultSelected="selected"
   @changeSelected="changeSelected"  // fix the property using camelCase
  ></v-select-child>
</template>

<script>
import { mapState } from "vuex";
export default {
  data() {
    ...
  },
  computed: {
    ...mapState({
      list: state => state.list
    })
  },
  methods: {
    changeSelected(val) {   // val: changed object value
      this.$store.dispatch("setSelected", { id:val.id });
    }
  }
};
</script>
Doyoun
  • 89
  • 1
  • 11
0

You can also use watch;

  <v-select
    :label="label"
    :items="list"
    v-model="selected"
    item-value="id"
    item-text="name"
  ></v-select>
</template>

...
watch:{
   selected(){
      this.$emit('changeValue', this.selected.id');
   }
}
...

and from parent;

<child @changeValue="id = $event" .. />