-
Notifications
You must be signed in to change notification settings - Fork 765
Description
Problem description
Updating a viewModel with a computed property from propertyA and propertyA at the same time ensures that either one will be fetched from the cache and it won't get updated
function DerivedViewModel(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
}
var mapping = {
bundlemodels: {
key: function(data) {
return ko.utils.unwrapObservable(data.id)
},
create: function(options) {
debugger
return new DerivedViewModel(options.data)
}
}
}
function ViewModel(data) {
var self = this;
// Bundle is a JS object
// Say we want to unpack the bundle data to create a list of viewmodels instead of creatng a viewmodel
data = Object.assign(data, {
'bundlemodels': self.extractFromBundle(data.bundle || {})
})
var vmData = Object.assign({
bundle: {}
}, data)
ko.mapping.fromJS(vmData, mapping, self);
}
ViewModel.prototype = {
/**
* Return an Array of data from the bundledata to track all updates in an observableArray
*/
'extractFromBundle': function(bundleData) {
return Object.values(bundleData)
},
/**
* Since the Object was created with the bundle extracted, the update flow should do the same
* The issue here is that the bundle data contains the very same data as the items that would
* be extracted from it. This triggers the alreadyMapped line inthe updateViewModel of the ko.mapping
* causing my mapped item not to be updated
*/
update: function(data) {
var self = this;
data = Object.assign(data, {
'bundlemodels': self.extractFromBundle(data.bundle || {})
})
ko.mapping.fromJS(data, self)
}
}
var viewModelData = {
bundle: {
id1: {
name: 'Amazing name',
id: 'id1'
},
id2: {
name: 'Amazing name2',
id: 'id2'
}
}
}
var updatedViewModelData = {
bundle: {
id1: {
name: 'Amazing name',
id: 'id1'
},
id2: {
name: 'Amazing namechanged',
id: 'id2'
}
}
}
var initialViewModel = new ViewModel(viewModelData)
var updatedViewModel = new ViewModel(viewModelData)
updatedViewModel.update(updatedViewModelData)
Following my explanation:
updatedViewModel.bundle and updatedViewModel.bundlemodels contain the same data. When bundle is checked for updating: this model data is cached.
When updating the bundlemodels, it retrieves the cacheddata and says it no longer has to update it.
This leaves updatedViewModel behind with only one of the two properties being properly updated
Calling the update function:
- Loops over the bundle object, makes everything observable and caches all these values within the simpleobject
- Loops over the bundlemodels array, checks if the objects currently exist within the cache (it does, because the same model was applied for the bundle object) and it does not update the bundlemodels
The reason for the 'computed' of the bundle object is to have an array with models that are persistent (checking on the key function). The bundle object can not be used to achieve this...
It is an issue that I'm currently facing in my code
Workaround:
The only solution for me is to skip making the bundle object observable. Specifying it within the copy array of the mapping solves my caching issue.
Other solution:
If you'd require both properties to be observable, the copy cannot be used. For that, you'd need to derive the other property from the copy of the original one (they won't reference the same instance then)