Related Posts
Building an efficient subscription for knockout computed observables
Extending Ryan Niemeyer’s protectedComputed
Changing an observableArray in 1 notification
How to Use Knockouts Computed Observables with the Mapping Plugin
Handling Server Side Exceptions During Ajax Requests

This is a blurb on using knockout‘s computed observables on a collection of items that are made observable via the mapping plugin. If you haven’t seen KnockoutJS then immediately go and watch all the demo / intro videos you can. You’ll be extremely impressed!

It’s easy to setup a computed observable in knockout, something like the full name example from their site works well.

// set our viewModel to be the result of an inline, immediately executing function,
//   so we can closure over private variables if we want
var viewModel = function() {
    // todo: private variables here

    return {
        firstName: ko.observable("Bob"),
        lastName: ko.observable("Smith")
    };
}();

// define the fullName computed observable
viewModel.fullName = ko.computed(function() {
    return this.firstName() + " " + this.lastName();
}, viewModel);

ko.applyBindings(viewModel);
firstName: <span data-bind="text: firstName"></span> <br />
lastName: <span data-bind="text: lastName"></span> <br />
fullName: <span data-bind="text: fullName"></span>

jsFiddle here

This gets a little more complex when we’re trying to render a list of items, but fortunately they have just the right extension point for us to work off of. On the mapping plugin page, they specifically recommend using the create callback for just this scenario:

Advanced usage

Sometimes it may be necessary to have more control over how the mapping is performed. This is accomplished using mapping options. They can be specified during the ko.mapping.fromJS call. In subsequent calls you don’t need to specify them again.

Of course, inside the create callback you can do another call to ko.mapping.fromJS if you wish. A typical use-case might be if you want to augment the original JavaScript object with some additional computed observables

I was so excited when I read that, yeah the code is a little verbose but it’s exactly what I’d wanted to accomplish – awesome.

My overall goal was to add the computed observable and make sure the mapping plugin made the rest of the properties on the object observable. To accomplish this, we have an object literal that has our custom configuration.

The create callback is immediately returning a new instance of a function that was defined inline and since the context (“this”) is the individual item in the array, we’re able to use “this” creatively. Like using it to access firstName and lastName, as well as using it to specify the scope of the computed observable.

// simulate some data coming back from an ajax request
var simulatedAjaxData = {
    'persons' : [
        { firstName: "John", lastName: "Smith" },
        { firstName: "Sgt.", lastName: "Shiney-Sides" },
        { firstName: "Rusty", lastName: "Schacklefurt" }
    ]
};

// specifies the create callback for the 'persons' property
var mappingOptions = {
    'persons': {

        // overriding the default creation / initialization code
        create: function (options) {

            // immediately return a new instance of an inline-function.  We're doing this so the
            //     context ("this"), is correct when the code is actually executed.
            //     "this" should point to the item in what will be the observable array.
            //     I put a few more parens in here to make things a little more obvious
            return (new (function () {

                // setup the computed binding
                this.fullName = ko.computed(function () {
                    return this.firstName() + ' ' + this.lastName();
                }, this);

                // let the ko mapping plugin continue to map out this object, so the rest of it will be observable
                ko.mapping.fromJS(options.data, {}, this);
            })(/* call the ctor here */));
        }
    }
};

var viewModel = ko.mapping.fromJS(simulatedAjaxData, mappingOptions );

ko.applyBindings(viewModel);?
<ul>
    <!-- ko foreach: persons -->
    <li data-bind="text: fullName"></li>
    <!-- /ko -->
</ul>

Here is the the jsFiddle.

All we really did in that constructor / function was to create the the computed observable and to tell it to continue parsing the object.

Now we have the ability to add anything we want to each item as we parse the data. So now working with computed observables is extremely easy, even when they need to be added to an array parsed by the knockout mapping plugin.

Related Posts
Building an efficient subscription for knockout computed observables
Extending Ryan Niemeyer’s protectedComputed
Changing an observableArray in 1 notification
How to Use Knockouts Computed Observables with the Mapping Plugin
Handling Server Side Exceptions During Ajax Requests