I have the following blade file:
@extends('layouts.app') @section('content') <div class="container"> <div class="row"> <div class="col-xs-12 col-sm-12 col-md-12 col-lg-8 col-xl-7 mx-auto"> <items :items="{{ $items }}" /> </div> </div> </div> @endsection
where $items
is a JSON array of objects pulled from the controller. Now, the items
component looks like this:
<template> <div> <item v-for="(item, key) in computedItems" :key="key" :item="item"/> </div> </template>
The computedItems
property looks like:
computed: { computedItems() { // referring to the prop that is passed from the blade file let items = this.items; if (this.filterOptions.type !== 'Clear') { items = items.filter(i => i.status === this.filterOptions.type); } if (this.searchOptions.query.trim() !== '') { items = items.filter( i => i.name.toLowerCase().indexOf(this.searchOptions.query.toLowerCase()) !== -1 ); } if (this.sortOptions.type === 'asc') { items.sort((a, b) => a.id - b.id); } else if (this.sortOptions.type === 'desc') { items.sort((a, b) => b.id - a.id); } return items; } }
In item
sub-component you have the ability to delete items
through a method as follows:
methods: { _delete() { const _confirm = confirm('Are you sure you want to delete this item?'); if (!_confirm) { return; } axios.delete(`/items/${this.item.id}`).then(response => { this.$eventBus.$emit('deleted', { id: this.item.id }) }); } }
The event gets picked up by the parent (items
component) and is handled:
deleted(item) { const i = this.items.findIndex(_i => item.id === _i.id); this.items.splice(i, 1); }
But for some reason, the DOM is not updating and the v-for
is still displaying the deleted object, though, if I dump the prop, it shows that it has been amended. My suspicion is that Vue can’t tell that the object has been modified because it is part of props
and not a data
. I’ve tried the following:
- Using
Vue.delete
instead ofArray.splice
- Using
this.$delete
instead ofArray.splice
- Using
Array.splice
on the computed prop instead of the prop - Setting watchers
- Expanding the computed properties to accept a getter and setter
- A whole lot of searching on the Vue forums
Now, I understand you can’t mutate a prop directly because that’s anti-pattern, so I used a computed prop, but still, my changes aren’t reflected in the DOM.
So, why is the DOM not updating?
Advertisement
Answer
Posting my comment as requested and I’ll list the key points of the topic:
One Way Data Flow: No prop mutation. If there’s a prop you need to mutate locally in a component, first clone it to data and mutate the clone.
Use Vuex instead of an event bus for state/event management
Vuex allows for global state which can be mutated via actions, in a controlled fashion, from within a component (or elsewhere). Data flows down from the store and emits up through mapped/called actions.