vue: Ability to disable/not trigger watch handler on data?
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:
watch: {
todos: {
deep: true,
handler: todoStorage.save,
},
},
Triggering todoStorage.save
would 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 undefine
the handler while making the operation doesn’t work.
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 9
- Comments: 29 (2 by maintainers)
I made a mixin which brings a
$withoutWatchers()
method. This method disables the watchers within its callback :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 :
Here is the mixin
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 ?
It should be pretty obvious at this point that this would be a rather useful feature in many situations.
Ugly:
Nice:
Nice >> Ugly
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’d rather have some kind of
source
added to the watch. Something along the lines ofHello, 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 📝 What i want is to fire change only when i manually change the value into the textarea. Here, the ‘code’ variable will call onUpdateCode on sync change every time => not what i want 🐛 . And the ‘coder’ variable will not call onUpdateCoder because i did add a dirty silence mechanism. And onUpdateCoder is only called when i do change text into the coder textarea. The coder is what i want 🍎 (i tried a better solution with Vue.nextTick, but it fail, i think it could have worked if Vue.nextTick can dispatch by setting a priority parameter)
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 : https://github.com/ajaxorg/ace/issues/503#issuecomment-163761023 The next comment from @davidthornton notice it’s a https://en.wikipedia.org/wiki/Operational_transformation logic.
@yyx990803, you did already answered this in this issue : https://github.com/vuejs/vue/issues/1157 But it’s not really this case here.
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
unwatch
function, which I can call it when I want to stop watch, after that I watch the value again, it’s terrible…For anyone finding this still using Vue 2, as of 2.7.x abellion’s solution above needs to be changed to:
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 …
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.
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.
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: