-
-
Save BinarySpike/aa4f82fd024265b72fcde1327c7b0f09 to your computer and use it in GitHub Desktop.
Vue error when wrapping model in ObservableSlim
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>ObservableSlim with Vue Error</title> | |
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script> | |
<script src="js/ObservableSlim.js"></script> | |
</head> | |
<body> | |
<div id="app"> | |
{{ model }} | |
</div> | |
<script> | |
var app = new Vue({ | |
el: '#app', | |
data: { | |
model: | |
{ | |
messageArray: [], | |
messageText: "unchanged", | |
} | |
} | |
}) | |
function vueChange(changes) { | |
// applies changes to the underlying vue model | |
changes.forEach(function (item) { | |
//let path = item.currentPath.substring(0, item.currentPath.lastIndexOf(".")); | |
let prop = item.currentPath.substring(item.currentPath.lastIndexOf(".") + 1, item.currentPath.length); | |
Vue.set(item.target, prop, item.newValue); | |
}); | |
} | |
function noChange(changes) { | |
// do nothing | |
// specifically: do not call Vue.set | |
} | |
function copyChange(changes) { | |
// copies changes onto the base model, implies item.target does not point to app.model | |
changes.forEach(function (item) { | |
let path = item.currentPath.substring(0, item.currentPath.lastIndexOf(".")); | |
let prop = item.currentPath.substring(item.currentPath.lastIndexOf(".") + 1, item.currentPath.length); | |
let obj = _.get(app.model, path) || app.model; // when path is empty, _.get returns undefined. Coalesce into the base value. | |
Vue.set(obj, prop, item.newValue); | |
}); | |
} | |
function test1() { | |
// creates a 'default' obslim with domDelay and lets obslim commit the changes | |
// messageDelayedNewProp never appears in the model (non-reactive) | |
let dataModel = ObservableSlim.create(app.model, true, noChange); | |
dataModel.messageText = []; | |
dataModel.messageText.push("Test"); // works | |
setTimeout(function () { // delay to simulate dom event or devconsole changes. | |
dataModel.messageDelayedNewProp = { test: "Test" }; // not reactive! | |
}, 500); | |
} | |
function test2() { | |
// creates a 'default' obslim as above, but makes an immediate non-reactive change and a delayed non-reactive change. | |
// observable/proxy/obslim is intended to handle non-reactive changes and make them reactive. | |
// neither InitialNewProp nor messageDelayedNewProp appear on the model | |
let dataModel = ObservableSlim.create(app.model, true, noChange); | |
dataModel.InitialNewProp = {} // is not reactive, does not show up | |
setTimeout(function () { // delay to simulate dom event or devconsole changes. | |
dataModel.messageDelayedNewProp = { test: "Test" }; // not reactive! | |
}, 500); | |
} | |
function test3() { | |
// creates a 'default' obslim as above, but makes an immediate non-reactive, reactive, non-reactive, then delayed non-reactive change. | |
// immediate non-reactive are 'magically' reactive, while delayed remains non-reactive. | |
// That is, the non-reactive InitialNewProp and SubsequentNewProp appear magically but messageDelayedNewProp doesn't | |
let dataModel = ObservableSlim.create(app.model, true, noChange); | |
dataModel.InitialNewProp = {} // is reactive...?? | |
dataModel.messageText = []; | |
dataModel.messageText.push("Test"); | |
dataModel.SubsequentNewProp = {}; // reactive and shows up!? | |
setTimeout(function () { // delay to simulate dom event or devconsole changes. | |
dataModel.messageDelayedNewProp = { test: "Test" }; // not reactive! | |
}, 500); | |
} | |
function test4() { | |
// same as above, but pauses changes: Pause is needed because ObservableSlim does not respect Vue reactivity | |
// additionally, we use a new handler/notify callback that calls Vue.set to wire up reactivity correctly | |
// unfortunately, fails because array is not created before attempts are made to resolve members | |
let dataModel = ObservableSlim.create(app.model, true, vueChange); | |
ObservableSlim.pauseChanges(dataModel); | |
dataModel.InitialNewProp = {} // works with vueChange | |
dataModel.messageText = []; | |
dataModel.messageText.push("Test"); // Push fails to resolve because messageText hasn't been changed to an array yet. | |
} | |
function test5() { | |
// same as above, but uses `messageArray` to forgo creating an array. | |
// while it resolves the array problem this reveals another problem | |
let dataModel = ObservableSlim.create(app.model, true, vueChange); | |
ObservableSlim.pauseChanges(dataModel); | |
dataModel.messageArray.push("Test"); // Fails due to vue error. Documentation indicates it's not resolving `this` | |
} | |
function test6() { | |
// same as above, but uses noChange to determine if ObservableSlim is the issue. | |
// the object is paused and Vue.set is no longer called, meaning no changes should be made. | |
// this should be an immutable operation! | |
let dataModel = ObservableSlim.create(app.model, true, noChange); | |
ObservableSlim.pauseChanges(dataModel); | |
dataModel.messageArray.push("Test"); // Fails with same weird vue issue | |
} | |
function test7() { | |
// The only configuration that works for all my test cases | |
let dataModel = ObservableSlim.create(app.model, false, vueChange); // only interation that works | |
ObservableSlim.pauseChanges(dataModel); | |
dataModel.NewProp = {} // works! | |
dataModel.messageText = []; | |
dataModel.messageText.push("Test"); // works! | |
setTimeout(function () { // delay | |
dataModel.messageArray.push("Test"); // works! | |
dataModel.delayedNewProp = {} // works! | |
}, 500); | |
} | |
function test8() { | |
// creates an ObservableSlim, but then works directly against the vue model | |
// this works, but observers are not notified | |
let dataModel = ObservableSlim.create(app.model, true, vueChange); | |
ObservableSlim.pauseChanges(dataModel); | |
setTimeout(function () { // delay for 3 seconds | |
app.model.messageArray.push("Test"); // works! | |
dataModel.messageArray.__getTarget.push("Test2"); // also works | |
}, 500); | |
} | |
function test9() { | |
// creates obslim first, then sets it on vue. Basically backwards of what we've been doing | |
// this doesn't quite work in theory because we now have to respect vue reactivity, though we have observables | |
// however, it actually doesn't work because vue fails with a similar error as test5 and test6 | |
let model = {messageArray:[]}; | |
dataModel = ObservableSlim.create(model, true, noChange); | |
//ObservableSlim.pauseChanges() // we are letting obslim make the changes to the base model through a reactive call to Vue | |
Vue.set(app, "model", dataModel); | |
app.model.messageArray.push("Test") // works | |
setTimeout(function () { // delay | |
app.model.messageArray.push("Test2") // fails! | |
}, 500); | |
} | |
function test10() { | |
// creates a model like above and binds observable slim. | |
// instead of referencing it to vue, we use a "copyChange" handler to change the vueModel from the observable. | |
// Test cases work successfully while domDelay is true! | |
let model = {messageArray:[], messageText:"unchanged"} // ~matches app.model | |
let dataModel = ObservableSlim.create(model, true, copyChange); | |
dataModel.messageArray.push("Test"); // works | |
dataModel.newArray = []; | |
dataModel.newArray.push("Test2"); // works!! (doesn't fail like test4) | |
setTimeout(function () { // delay | |
dataModel.messageArray.push("Test3") // works | |
dataModel.newProp = "Test" // works | |
}, 500); | |
window.dataModel = dataModel; | |
} | |
//test1(); | |
//test2(); | |
//test3(); | |
//test4(); | |
test5(); | |
//test6(); | |
//test7(); | |
//test8(); | |
//test9(); | |
//test10(); | |
</script> | |
</body> | |
</html> |
added tests test9
and test10
. Added new handler named copyChange
that copies changes from a base model to a vue model. Added lodash dependency
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updated comments for clarification. Expanded
test7()
to include non-reactive changes working properly along withArray.push