Arising from this discussion:
My suggestion was to create a “shield” observable value that gets used instead of route.data
.
This can be done something like:
AppVM = DefineMap.extend({
// the actual stateful values from the url
routeData: {default() { return new DefineMap() } },
// if we have some state where we don't want it to look like the url has changed right away
isSaving: "boolean",
// A getter used mostly so we can know when any data in the URL changed
get routeDataClone(){
return this.routeData.get()
},
// this will have the old `routeData` if isSaving is true:
shieldData: {
value({resolve, listenTo}){
// A place to store the last route data
var savedData;
// When the route data changes
listenTo("routeDataClone", function(ev, newData){
// if we are saving, save the new data
if(this.isSaving){
savedData = newData;
} else {
resolve(newData); // if we aren't saving, update
}
})
listenTo("isSaving", function(ev,newValue){
// when saving state changes to false
// check if there was some route changes and apply them
if(!newValue && savedData !== undefined) {
resolve(savedData);
savedData = undefined;
}
})
}
}
});
var appVM = new AppVM();
route.data = appVM.routeData;
Note, this doesn’t allow someone to change a shieldData
value and have it update the URL. For that sort of two-way binding, I would probably set this up in connectedCallback()
with the new can-bind
for 5.0:
routeData: { ... },
get routeDataClone() { ... }
shieldData: {...},
get shieldDataClone() { ... }
connectedCallback(){
var savedData;
var binding = new Bind({
parent: value(this, "routeDataClone"),
child: value(this,"shieldDataClone"),
updateParent: (shieldData) => {
this.routeData.update( shieldData )
},
updateChild: (shieldData) => {
if(!this.saving){
this.routeData.update( shieldData )
} else {
savedData = sheildData;
}
}
})
binding.start();
// LISTEN ON isSaving like the first code example
return binding.stop.bind(binding);
}