New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ability to disable/not trigger watch handler on data? #1829
Comments
|
The point of a watcher is that it will fire when the data changes. Instead of thinking about stopping it from firing, just do a conditional check inside the watcher callback. |
|
I wish I could @yyx990803 😢 In this case I cannot do a conditional check in the watcher callback since there's no way for me to check whether I'm going to receive more deletion messages via WebSocket which come one at a time. If every object in my
This results in errors on my backend because I'm trying to update data that no longer exists there. Is there a recommended Vue.js pattern for this? |
|
I don't think I understand your use case, but maybe using a deep watcher to persist the whole is just the wrong idea to begin with. You should probably use a component for each item in the array so you can do fine-grained persistence. |
|
Hello, i guess i understand the issue from @dalanmiller. In fact, i was stuck on a similar issue : the fact that you don't want the watcher trigger the callback every time when you manually decide to affect the value somewhere. For instance : i got my data from an rest api call in an async way. Then i decide to affect the data in my component, but the watcher detect change and will trigger the callback that notice update the changes to my rest api : there were no data change but i got an api 'Set' call ! 😕 More into this issue, i did a codepen to explain that (VueJS 2.0) : http://codepen.io/matyo91/pen/ZBpjVz I come to this code, because somehow, i got a similar issue when integrating ace.js into a VueJS component. And the ace team got the same issue and it's resolved by that comment from @nightwing : ajaxorg/ace#503 (comment) @yyx990803, you did already answered this in this issue : #1157 So i think it's more a design pattern issue. But now i don't know how to write it into a "smart code". Any idea ?! |
|
It seems I encounter a similar issue, my solution is that use this.$watch instead of watch option, this.$watch return a handler to |
|
Had the same issue. But I think the fix is simple. Just use the watch function to decide if you would like to call a method: // vue 1.0
this.$watch('myModel', function(newVal, oldVal) {
if([your statement]) {
this.loadSomeData();
}
}); |
|
I found that action of the firefox and chrome is different, in updated(), if the event was triggered, firefox fall into stuck and never come out, but chrome can deal with this correctly. |
|
whether you use $watch and unwatch, or set a flag to prevent the watch from handling, you'll need to wait for this.$nextTick() otherwise you will unwatch/turn off the flag prematurely and the watcher will still get executed. |
|
It should be pretty obvious at this point that this would be a rather useful feature in many situations. Ugly: Nice: Nice >> Ugly |
|
I'd rather have some kind of |
|
I like the idea of getting the source from the watch function(value, old, source). I have the same problem and there are only ugly solutions. |
|
Hello, here is what i'm doing for that problem. I had to face with reseting twice search and filters, without trigger multiple watch at the same time. Hope this helps ... |
|
I made a mixin which brings a $withoutWatchers(() => {
// Watchers will not get fired
})The following is a real world example of a user's form. We want this component to take the user as a prop, copy it in an internal value, dispatch the changes when this internal value is updated, and update the internal value when the prop changes : export default {
data: () => ({
model: null
}),
props: {
user: {
type: Object,
required: true
}
},
created () {
this.$watch('user', this.sync, {
immediate: true
})
},
methods: {
sync () {
this.$withoutWatchers(() => {
this.model = { ...this.user }
})
}
},
watch: {
model () {
this.$emit('update:user', this.model)
}
}
}Here is the mixin
const WithoutWatchers = {
methods: {
$withoutWatchers (cb) {
const watchers = this._watchers.map((watcher) => ({ cb: watcher.cb, sync: watcher.sync }))
for (let index in this._watchers) {
this._watchers[index] = Object.assign(this._watchers[index], { cb: () => null, sync: true })
}
cb()
for (let index in this._watchers) {
this._watchers[index] = Object.assign(this._watchers[index], watchers[index])
}
}
}
}Be aware that this mixin uses the internal Vue's API, which may change between minor versions. That would be cool to have it within Vue's core. Could we consider bringing it @yyx990803 ? |
|
@abellion wonderful solution to this problem. |
|
Nice work @abellion would love to get this added to vue |
|
@abellion really nice!
or |
I had tried to use |
|
@abellion THANK YOU! This is very helpful. Battling data properties and watchers has been a thorn in my side for a long time. |
|
i figured out another solution, in my small project, it works well... |
|
I don't know if this helps anyone but I needed a watcher that watches Working with |
|
In my case, I only wanted to watch a partial object.
|
|
There's a watchIgnorable in the vueuse library: https://vueuse.org/shared/watchignorable/ that allows you to stop the watch |
|
Here's a follow up to @abellion's solution. As abellion predicted, Vue's internal architecture seems to have changed between versions 2 and 3, and I found that the mixin no longer worked after upgrading. After a little digging, I found that the watchers had moved within Vue's hierarchy, but the basic premise appears to be same. Here's an updated version of @abellion's mixin. I believe this works correctly in Vue 3. However I strongly suggest that anyone deciding to adopt it should test it carefully. export default {
methods: {
$withoutWatchers (cb) {
const watchers = this._.type.watch;
for (let index in this._.type.watch) {
this._.type.watch[index] = Object.assign(this._.type.watch[index], { cb: () => null, sync: true })
}
cb()
for (let index in this._.type.watch) {
this._.type.watch[index] = Object.assign(this._.type.watch[index], watchers[index])
}
}
}
} |
|
For anyone finding this still using Vue 2, as of 2.7.x abellion's solution above needs to be changed to: export default {
methods: {
$withoutWatchers(cb) {
const watcher = {
cb: this._watcher.cb,
sync: this._watcher.sync,
};
this._watcher = Object.assign(this._watcher, { cb: () => null, sync: true });
cb();
this._watcher = Object.assign(this._watcher, watcher);
},
},
}; |
Thanks for pointing this out. I ran against the issue and was able to resolve it by using watchIgnorable in my Vue 3 application. Keywords: Parent initiated update alters property in child. Child UI to ignore updates as a result of the property change. Code |
|
Anyone got any ideas on how to do this in Vue 3 with the Composition API and the |
The code I linked to on 10/14 worked for me in this situation. |
Thank you! I'll take a look. :) |
For my application, I'm mutating the object in my
data: [{...}, {...}, {...}]to state changes occurring at other open instances of my application (happening through web sockets etc, etc). I have a handler on the data structure like this below:Triggering
todoStorage.savewould unnecessarily save the contents of the array back to my database where I already know the current state of the application.Is there a way to mutate the array without triggering the handler? It seems that trying to
undefinethe handler while making the operation doesn't work.The text was updated successfully, but these errors were encountered: