Q:

Mapping deeply nested array properties

Example jsFiddle

I have a model that is a Calendar at the root level. This Calendar contains many days, each Day contains an Event, each Event contains attendees and each Attendee has 0 or more Intolerances.
So it looks like this:
function Calendar(data) {
    this.days = ko.observableArray(data.days);
}

function Day(data) {
    this.date = ko.observable(data.date);
    this.event = ko.observable(data.event);
    this.daysToEvent = ko.computed(function () {
        var diff = Math.abs(new Date(), this.date());
        return (((diff / 1000) / 60) / 60) / 24;
    }, this);
}

function Event(data) {
    this.name = ko.observable(data.name);
    this.attendees = ko.observableArray(data.attendees);
}

function Attendee(data) {
    this.name = ko.observable(data.name);
    this.age = ko.observable(data.age);
    this.intolerances = ko.observable(data.intolerances);
}

function Intolerance() {
    this.id = ko.observable(data.id);
}

I'm passing a JSON string to this model and using the ko.mapping plugin (just started using it) to wire it all up.  What I'm not understanding though is how can I tell the plugin to use my objects during mapping?
I'm aware of the mapping options param, but at the moment I'm a newbie so not really "getting it" so to speak.  I've attempted with this:
var viewModel = {
    calendar: null,
    loadCalendar: function () {
        ko.mapping.fromJSON(json, {
            create: function (opts) {
                return new Calendar({ days: opts.data.calendar })
            }
        }, viewModel.calendar);
    }
};

Which gets my my Calendar object and the days, but how (and what is the most correct way) do I further map my classes down the tree?

A:

You can put the mapping code inside the ViewModels themself:
function Calendar(data) {
    this.days = ko.observableArray();

    // update the current ViewModel with the given data
    if (data) {
        ko.mapping.fromJS(data, {
            days: {
                // tell the mapping plugin how to create the days
                create: function(options) {
                    return new Day(options.data);
                }
            }
        }, this);
    }
}

function Day(data) {
    this.date = ko.observable();
    this.event = ko.observable();

    if (data) {
        ko.mapping.fromJS(data, {
            event: {
                create: function(options) {
                    return new Event(options.data);
                }
            }
        }, this);
    }

    this.daysToEvent = ko.computed(function () {
        var diff = Math.abs(new Date(), this.date());
        return (((diff / 1000) / 60) / 60) / 24;
    }, this);
}

...

