observable-slim
observable-slim copied to clipboard
Vue error when domDelay is set to true, when modifying array.
When using ObservableSlim on a Vue.js data model, I'm running into a vue error when domDelay is enabled & you don't make changes right away.
See this gist for a series of tests: https://gist.github.com/BinarySpike/aa4f82fd024265b72fcde1327c7b0f09
Ultimately I got it working (test7), but it seems ObservableSlim is doing something that Vue doesn't like (test5), even when I've called pauseChanges
and don't mutate the object myself (test6).
Below are the three issues I ran into.
- ObservableSlim does not respect Vue's reactivity.
pauseChanges
and then useVue.set
in the observable (this is the recommended vue way)
- Changing a variable to a complex type and then trying to resolve prototypes on it such as
Array
andArray.push
will fail in the same operation/batch
Disabling domDelay fixes this
- Some time after the an ObservableSlim is created on a VueJS model, using
Array.push
will generate a vue error.
Disabling domDelay fixes this, but it's not intuitive why.
My troubleshooting and intuition leads me to believe Vue is queuing/batching changes like ObservableSlim. Directly after creating the ObservableSlim, if you make changes, they are performed before Vue "wires-up." However, once Vue completes it's initial operations something is funky. It has something to do with the way ObservableSlim resolves/calls Array.push
because direct access (test8) works fine.
I think test7 will work for my immediate needs, but I would like to know if there are solutions to problems 2 and 3.
Thank you for the clean re-pro examples! I'll dive into this issue either tomorrow or this weekend and see what I can figure out. Off the top of my head, it sounds to me like Vue might be making additional mutations to the target object after the initial mutation. When domDelay
is set to false, then your handler function is invoked before Vue has the opportunity to make any additional mutations.
In general, I'd expect that Vue models won't play very nice with ObservableSlim -- especially Arrays. In order to observe mutations on plain objects, Vue 2 uses Object.defineProperty
-- but for arrays Vue wraps all of the mutation methods on the Array
object: https://vuejs.org/v2/guide/list.html#Array-Change-Detection -- Wrapping all of the mutation methods on an Array could cause some pretty strange behavior when used in conjunction with ObservableSlim's Proxy-based observer. ObservableSlim works best when observing plain objects or plain Arrays (with any degree of nesting) -- not so much when observing a complicated model built by Vue that is observing changes via defineProperty
and wrapping Array mutation methods.
Vue 3 will ship with a Proxy-based observer ( https://medium.com/the-vue-point/plans-for-the-next-iteration-of-vue-js-777ffea6fabf ) which might resolve the issues you've encountered.
Elliot, you made me realize I probably don't need to Observe my vue model directly. I can use a separate simple data model and directly modify the vue model from my handler. As long as both models have a matching initial starting value, they should transform the same.
Really loving ObservableSlim so far!
Edit
Been trying to solve how to bundle all my code as a nodejs module vs a browser include and saw this solution in ObservableSlim.js:
try { module.exports = ObservableSlim; } catch (err) {};
Glad to hear that you were able to find a workaround! I haven't had a chance to dive deep into this issue yet, but it's still on my to-do list.