Search code examples
knockout.jsknockout-mapping-plugin

Use ko.mapping to create an UN-observed array with observables?


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.


Solution

  • 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)...

    • It was slow on large view models, particularly in older browsers(IE7/8) and on large arrays. (not as big a deal…yet)
    • Creating viewmodels wasn't a one step process... after calling mapping you'd then have to extend the viewmodel further. (Occasionally, for small storage models, I didn’t need to do this, however for additional properties/functions I had this additional need to continue to follow our existing patterns.)
    • It provided no easy way to organize the viewmodel creation code which becomes a problem on larger viewmodels. (One of my biggest annoyances…I was really hoping using combinations of mapping options I could really cut down on the repetition of properties)
    • It didn't allow much customization in how the viewmodel was created and what customization there was was confusing and not intuitive to use. (The manipulation of the view model has been absolutely unavoidable. The timing/order of mapping procedures wasn’t always as predictable as I hoped it would be. Really gets confusing when you start cascading the mappings together.)

    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.