Hi,
I need to create directive that accepts a list (or array) binding - similar to v-repeat. Is there a recommended way of determining what actually has changed in such bound list?
Let's say I want to remove one element in the middle of the list. Is there API for detecting such changes?
Actually, if a list has changed, only three options are valid:
...or a combination of above. It would be great if there was some kind of built-in mechanism for detecting such changes for array-like parameters :)
when you do vm.$watch() on an array, the callback's second parameter is mutation. If it exists, it means the array itself mutated. It's an object containing the mutation info.
this.$watch('list', function (value, mutation) {
if (mutation) {
mutation.method // e.g. 'push'
mutation.args // raw arguments to the mutation method
mutation.result // return value
mutation.inserted // new, inserted elements
mutation.removed // removed elements
}
})
It works fine, many thanks! :)
when you do vm.$watch() on an array, the callback's second parameter is mutation
No it's not. In my component's created hook:
this.$watch('users', function(value, mutation) {
console.log(mutation);
});
Expected: log this mutation object you speak of
Actual: logs the array itself
Was this reverted?
Hi @CrescentFresh - this issue was made two years ago when Vue was at version 0.10. You can find the current docs for $watch here.
Reading the docs and looking at the relevant code I see there is no information made available to watchers to know what mutation event caused the array to change. Is that an accurate statement?
If so, :(
when you do
vm.$watch()on an array, the callback's second parameter ismutation. If it exists, it means the array itself mutated. It's an object containing the mutation info.this.$watch('list', function (value, mutation) { if (mutation) { mutation.method // e.g. 'push' mutation.args // raw arguments to the mutation method mutation.result // return value mutation.inserted // new, inserted elements mutation.removed // removed elements } })
I can confirm this feature doesn't exist anymore in Vue. So I've had to reproduce it myself.
The below code is not bulletproof but at least it detects arr.push, arr.splice and this.$set(arr, index, something) – I also set up a quick demo:
function eventify (arr) {
let eventify = function(arr) {
arr.isEventified = true;
// overwrite 'push' method
let pushMethod = arr.push;
arr.push = function(e) {
pushMethod.call(arr, e);
// the user added something into the array using 'push'
// so at this point I can trigger my own code
};
// overwrite 'splice' method
let spliceMethod = arr.splice;
arr.splice = function() {
let args = [], len = arguments.length;
while (len--) args[len] = arguments[len];
spliceMethod.apply(arr, args);
let idx = args[0];
let nbDel = args[1];
let elemsLen = args.length - 2;
if (elemsLen === 0) {
// we reach this part of the code when the user removed some elements from the array
nbDel += idx;
while(idx < nbDel) {
// element at position 'idx' has been deleted
idx++;
}
}
else if (elemsLen > 0) {
// we reach this part of the code when the user used this.$set(list, i, "new value")
for (let i=2; i<elemsLen+2; i++) {
// element at position 'idx' has been changed
idx++;
}
}
};
};
// make sure we don't "eventify" this array
if (!arr.isEventified) eventify(arr);
}
// watch the array called 'list'
this.eventify(list);