Reputation: 8428
I am setting up my model with the ko.mapping utility.
When passing in my primary data, consider one of my properties to be an array. This array is one object per 7 days of the week, so I know this set will not change nor be rearranged. I can easily generate this array as either a copy of the JSON object with flatted properties or as an observableArray with either observed or flat properties, but what I can't seem to do through the mapping utility is create a flat array with a mix of both basic properties and observed properties.
I have attempted various permutations of mapping options, but it still looks as though I'm going to have to map this array without or just bite my incessant and anal urge to have this complex model mapped exactly how I want it in the way I want to map it.
To better show the issue:
var PrimaryViewModelMapping = {
copy: ['KeyProperty', 'ArrayOfDays'],
create: function(options) { return new PrimaryViewModel(options.data); }
}
This will give me a flat copy of the array in my instance of the PrimaryViewModel without any extra effort...but no control over the properties within the ArrayOfDays without looping through the array in my declaration of PrimaryViewModel and doing stuff.
To continue:
var PrimaryViewModelMapping = {
copy: ['KeyProperty'],
observe: ['ArrayOfDays'],
create: function(options) { return new PrimaryViewModel(options.data); }
}
This will nicely package up my ArrayOfDays as an observable array yet keep all of its 'each' properties flattened.
The next attempt was the following:
var PrimaryViewModelMapping = {
copy: ['KeyProperty'],
'ArrayOfDays': {
copy: ['Date'],
observe: ['TotalDuration'],
create: function(options) {
return new DayArrayModel(options.data);
}
}
}
This makes an observable array and gives me full control over what is observed (TotalDuration) and what isn't observed (KeyProperty) and within the declaration of my object DayArrayModel, just about anything else I may want to do...
BUT the ArrayOfDays is still an observable Array. I don't need nor really want it to be.
Understand that the topic here is specific to the mapping plugin and I don't want to create loops within the PrimaryViewModel declaration to handle this...which I know I could do. Just wondering if I've stumbled upon a 'feature-request' or if I'm simply not getting it.
Thanks.
Upvotes: 0
Views: 1295
Reputation: 8428
I came to a wall with the topic of mapping in Knockout. I did climb this wall, however I remain perplexed. From the perspective of an advanced use case, the mapping plugin seems to do nothing more than obfuscate the connection between the data and the viewModel bound by Knockout.
I discovered the list below (and added comments) from http://www.coderenaissance.com/ which also seems to have another variation of a mapping plugin that seems to not have gotten much attention of yet. I do like the creator's insight, for it meshes well with my own experience(s)...
So, the punchline for my first question...or joke, as it seems to me now...is that there is no spoon. As a result of my findings, I removed the attempt to use ko.mapping to act as my schema initialization and only use it for prepping my initial trigger from the view before my ko.applybindings command. At this point, I use a combination of arrayMap and observable(array) to fill my objects...just like I used to. For now, I've gained the knowledge of when not to use the mapping plugin.
Upvotes: 0
Reputation: 63830
If you insist on wanting to prevent the ArrayOfDays to be a regular array, you could utilize the ko.utils.arrayMap
method. However, what you want goes quite against what the mapping plugin does, so it's going to get a bit verbose.
The problem is that mapping options don't allow you to specify how individual properties are constructed, you can only tell the plugin to include or exclude properties, or how to generate elements in an array. So your first step is not to generate the main view model directly. Instead, you could do this:
var MainViewModel = function(data) {
var self = this;
var mappingOptions = {
'exclude': ['ArrayOfDays']
};
// Map everything, except the array
ko.mapping.fromJS(data, mappingOptions, self);
// Do the array itself, but prevent it from becoming an *observable* array
self.ArrayOfDays = ko.utils.arrayMap(data.ArrayOfDays, function(item) { return new DayViewModel(item); });
};
This does a few things:
self
to prevent any nasty this
issues;self
.The key here is that ko.utils.arrayMap
will return a flat array, not an observableArray.
Here's a fiddle to demonstrate this.
As a foot note, it's unclear to me why you'd want something like this (premature optimization perhaps?).
Upvotes: 2