I'm trying to build a simple task management app with Vue and Electron. My setup is based on the electron-vue boilerplate with Vuex store. The user can add new items to the list (and edit existing items) through a modal. The modal sends the information to a store action which then calls a mutation to update the store and push a new item to the list item array.
This is the setup: LayerItem
is a child of Layer
which is a child of LayerMap
. Data is received from the store within the parent LayerMap
component and then provided to children via props.
Recreating the issue: Create a new item via the showEditItemDialog
in Layer
component. Within the SAVE_LAYER_ITEM
mutation, a new ID will be created and assigned to that new item. After that, the new item will be pushed to the layer.items
array. The UI will be updated and the created item is visible. item.text
is displayed correct. The item.id
however is different. I included a console.log
within the mutation. The logged id doesn't match the id displayed in the UI within the LayerItem
component here <p>{{ item.id }}</p>
. As a result, when trying to edit/update a new item after it has been created, instead of updating the existing item, the mutation will create a new item since the ID received by the modal can't be found in the store array.
I know it's a lot of code, I tried to remove as much unnecessary code as possible. In the example below, I created a new item "test" and you can see that the stored ID doesn't match the ID displayed in the UI.
Screenshot from the Terminal logs
Screenshot from the DevTools console
Screenshot from Vue DevTools store
LayerMap.vue
// 'layers' is a computed property and gets data from the store
<draggable
v-model="layers"
v-bind="getDragOptions"
>
<Layer v-for="(layer, index) in layers" :key="index" :layer="layer"></Layer>
</draggable>
<DetailsModal></DetailsModal>
// Inside computed
computed: {
layers() {
return this.$store.getters.allLayers
}
}
Layer.vue
// 'layer' gets passed from parent as prop
<span primary-focus @click="showEditItemDialog">Add Item</span>
<draggable v-model="items" v-bind="dragOptions" class="items">
<LayerItem v-for="item in items" :item="item" :layer="layer" :key="item.id"></LayerItem>
</draggable>
// 'items' is a computed property
items: {
get() {
return this.layer.items
}
}
// Function to handle 'Add Item' click and send event which will be handled by DetailsModal.vue
methods: {
showEditItemDialog() {
let payload = {
layer: this.layer,
item: {
id: '',
text: ''
}
}
this.$bus.$emit('item-editing', payload)
}
}
LayerItem.vue
// Layer Item Component
<div class="layer-item" @click.prevent="startEditing">
<div class="item-body">
<p>{{ this.item.text }}</p>
<p>{{ item.id }}</p>
</div>
</div>
// Event will be sent on click with layer item details as parameter
methods: {
startEditing() {
let payload = {
layer: this.layer,
item: {
id: this.item.id,
text: this.item.text
}
}
this.$bus.$emit('item-editing', payload)
}
}
}
DetailsModal.vue
// 'editLayerForm' contains layer item id and text
<p>{{editLayerForm.id}}</p>
<div class="bx--form-item">
<input
type="text"
v-model="editLayerForm.text"
/>
</div>
// Inside <script>, event is received and handled, 'editLayerForm' will be updated with payload information
mounted() {
this.$bus.$on('item-editing', this.handleModalOpen)
},
methods: {
handleModalOpen(payload) {
this.layer = payload.layer
this.editLayerForm.id = payload.item.id
this.editLayerForm.text = payload.item.text
this.visible = true
console.log('editing', payload)
},
handleModalSave() {
let payload = {
layerId: this.layer.id,
item: {
id: this.editLayerForm.id,
text: this.editLayerForm.text
}
}
console.log('save', payload)
this.$store.dispatch('saveLayerItem', payload)
}
}
Store.js
const actions = {
saveLayerItem: ({ commit }, payload) => {
console.log('action item id', payload.item.id)
commit('SAVE_LAYER_ITEM', payload)
}
}
const mutations = {
SAVE_LAYER_ITEM: (state, payload) => {
let layer = state.map.layers.find(l => l.id === payload.layerId)
let itemIdx = layer.items.findIndex(item => item.id === payload.item.id)
console.log('mutation item id', payload.item.id)
if (itemIdx > -1) {
// For existing item
console.log('update item', payload.item)
Vue.set(layer.items, itemIdx, payload.item)
} else {
// For new item
payload.item.id = guid()
console.log('save new item', payload.item)
layer.items.push(payload.item)
}
}
}