Vuejs and Vue.set(), update array
VueJS can't pickup your changes to the state if you manipulate arrays like this.
As explained in Common Beginner Gotchas, you should use array methods like push, splice or whatever and never modify the indexes like this a[2] = 2
nor the .length property of an array.
new Vue({ el: '#app', data: { f: 'DD-MM-YYYY', items: [ "10-03-2017", "12-03-2017" ] }, methods: {
cha: function(index, item, what, count) { console.log(item + " index > " + index); val = moment(this.items[index], this.f).add(count, what).format(this.f);
this.items.$set(index, val) console.log("arr length: " + this.items.length); } }})
ul { list-style-type: none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script><div id="app"> <ul> <li v-for="(index, item) in items"> <br><br> <button v-on:click="cha(index, item, 'day', -1)"> - day</button> {{ item }} <button v-on:click="cha(index, item, 'day', 1)"> + day</button> <br><br> </li> </ul></div>
Vuejs - update array of an object which is in an array
I could update the stages reactively. Here is my full code; I used the push
method of an array object and it works:
<template>
<div>
<li v-for="item in stages" :key="item.stageId">
{{ item }}
</li>
</div>
</template>
<script>
export default {
data() {
return {
stages: [],
};
},
methods: {
async getTeamStages() {
this.stages = [{ stageId: 1 }, { stageId: 2 }];
for (let stage of this.stages) {
this.$set(stage, "tickets", []);
}
for (let stage of this.stages) {
await this.getStageTickets(stage);
}
},
async getStageTickets(stage) {
const tickets = ["a", "b", "c"];
for (let ticket of tickets) {
this.stages[this.stages.indexOf(stage)].tickets.push(ticket);
}
},
},
mounted() {
this.getTeamStages();
},
};
</script>
It should be noted that I used the concat
method of an array object and also works:
this.stages[this.stages.indexOf(stage)].tickets = this.stages[this.stages.indexOf(stage)].tickets.concat(tickets);
I tried your approaches some of them work correctly:
NOT WORKED
this.$set(this.stages[this.stages.indexOf(stage)].tickets, tickets)
WORKED
this.$set(this.stages[this.stages.indexOf(stage)].tickets, 0, tickets[0]);
WORKED
stage.tickets = tickets
this.stages.splice(this.stages.indexOf(stage), 1, stage)
I'm sure it is XY problem..
Vuejs and Vue.set(), update an Key/Value array
Since the edit
properties in your rows
objects are already set, you do not need to use Vue.set
in this case. You can just set the property value and Vue will notice the change:
this.rows[0].edit = false;
Here's a simple example:
new Vue({
el: '#app',
data() {
return {
rows:[
{ "id": "4", "edit": true },
{ "id": "5", "edit": false }
],
}
},
methods: {
editNext() {
let index = this.rows.findIndex(r => r.edit);
this.rows[index].edit = false;
let next = ++index % this.rows.length;
this.rows[next].edit = true;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<div id="app">
<div v-for="(row, i) in rows" v-if="rows[i].edit">
Editing Row ID {{ row.id }}
</div>
<button @click="editNext">Edit Next</button>
</div>
Vue.js Update Array not working using this.$set
I found the problem, Actually the property ListItem1 was not in the original Json so vue was not recognizing. what I did was use vue.$set correctly, was using Wrong
both work
this.$set(proj,"ListItem1",response.data.value);
Vue.set(proj,"ListItem1",response.data.value);
vue.js best way to update entire array
As suggested I will repond to this myself to help anyone in the same predicament.
oldArr = newArr
should still work (thank you choasia. Even though it is somewhat unclear in the vue.js documentation. Replacing the entire array will not fall under the caveats mentioned there (thank you Roy J ).
One option might also be to to empty the array and then push the new one like:
yourArray.push(... yourNewArray)
Thank you reiner
Array of objects - correct way of updating an object within the Vue.js ecosystem
This is a limitation of Vue's reactivity regarding arrays.
See #2 of Why isn’t the DOM updating?
When you modify an Array by directly setting an index (e.g.
arr[0] = val
) or modifying its length property. Similarly, Vue.js cannot pickup these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience methodarr.$set(index, value)
which is syntax sugar forarr.splice(index, 1, value)
You can solve this by using Vue.set
or Array.splice
in your module:
import Vue from 'vue'
// find the block's index in the array
const index = state.contentBlocks.findIndex(block => block.id === contentBlock.id)
// using Vue.set
Vue.set(state.contentBlocks, index, contentBlock)
// using Array.splice
state.contentBlocks.splice(index, 1, contentBlock)
Updates to object inside array do not trigger updates
First things first.
Using Vue.set
isn't going to help. Vue.set
is used to set the values of properties that Vue's reactivity system can't track. That includes updating arrays by index or adding new properties to an object but neither of those apply here. You're updating an existing property of a reactive object, so using Vue.set
won't do anything more than setting it using =
.
Next...
Vue does not take copies of your objects when passing them as props. If you pass an object as a prop then the child component will get a reference to the same object as the parent. A deep
watcher will trigger if you update a property within that object but it's still the same object. The old and new values passed to the watcher will be the same object. This is noted in the documentation:
https://v2.vuejs.org/v2/api/#vm-watch
Note: when mutating (rather than replacing) an Object or an Array, the old value will be the same as new value because they reference the same Object/Array. Vue doesn’t keep a copy of the pre-mutate value.
As you've noticed, one solution is to use a totally new object when performing the update. Ultimately, if you want to compare the old and new objects then you have no choice but to make a copy of the object somewhere. Taking a copy when mutating is a perfectly valid choice, but it's not the only option.
Another option would be to use a computed property to create the copy:
new Vue({
el: '#app',
data () {
return {
params: {
name: 'Lisa',
id: 5,
age: 27
}
}
},
computed: {
watchableParams () {
return {...this.params}
}
},
watch: {
watchableParams (newParams, oldParams) {
console.log(newParams, oldParams)
}
}
})
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
<input v-model="params.name">
<input v-model="params.id">
<input v-model="params.age">
</div>
VueJS2 : Push items into array and only update if property has changed
You have to assign the values of the object instead of pushing to array when the object is already in array.
language(x) {
// this.formValues.push(x);
let el = this.formValues.find((e) => e.P_uniqueID === x.P_uniqueID);
if (el) {
Object.assign(el, x);
} else {
this.formValues.push(x);
}
this.$emit("languages", this.formValues);
}
Working codesandbox
Related Topics
How Is JavaScript Single Threaded
JavaScript Getelementbyid() Not Working
Var Name Produces Strange Result in JavaScript
How to Stop Babel from Transpiling 'This' to 'Undefined' (And Inserting "Use Strict")
Array.Length Is Zero, But the Array Has Elements in It
Calling Setstate in a Loop Only Updates State 1 Time
Split String Only on First Instance of Specified Character
Classical Inheritance VS Prototypal Inheritance in JavaScript
Node.Js Tail-Call Optimization: Possible or Not
Undefined Values in Array(Len) Initializer
Search Recursively for Value in Object by Property Name
How to Build Query String with JavaScript
Convert Js Object to Form Data
Window.Onunload Is Not Working Properly in Chrome Browser. Can Any One Help Me
Is a JavaScript Array Index a String or an Integer