Mapping plugin Create callback, and adding new objects to view model

https://groups.google.com/d/topic/knockoutjs/Teiur2dlenA/discussion

by gurkavcu

HTML

<script src="https://github.com/downloads/SteveSanderson/knockout/jquery.tmpl.js"></script>
<script src="http://github.com/downloads/SteveSanderson/knockout/knockout-1.1.2.js"></script>
<script src="https://github.com/SteveSanderson/knockout.mapping/raw/master/build/output/knockout.mapping-latest.js"></script>
<ul data-bind="template: { name: 'itemTmpl', foreach: items }"></ul>
<script id="itemTmpl" type="text/html">
    <li>
        ID: <input data-bind="value: id" />
        Name: <input data-bind="value: name" />
        Category: <span data-bind="text: category"></span>
        Subcategory: <select data-bind="options: subcategories, value: subcategory"></select>
    </li>
</script>

<hr/>
<h2>ko.toJSON</h2>
<div data-bind="text: ko.toJSON(viewModel.items)"></div>

CSS

input { margin: 2px; width: 75px; }
ul { margin-left: 10px; }

JavaScript

var originalData = {
    categoryData: [
        { category: "a", subcategories: ["a1", "a2", "a3"]},
        { category: "b", subcategories: ["b1", "b2", "b3"]},
        { category: "c", subcategories: ["c1", "c2", "c3"]}
    ],
    items: [
        { id: 1, name: "One", category: "a", subcategory: "a2"},
        { id: 2, name: "Two", category: "b", subcategory: "b3"},
        { id: 3, name: "Three", category: "c", subcategory: "c1"}
    ]
};


function Item(item) {
    this.id = item.id;
    this.name = ko.observable(item.name);
    this.category = ko.observable(item.category);
    this.subcategory = ko.observable(item.subcategory);

    //deferEvaluation, as this is getting created in the mapping plugin and some of our data is not ready
    this.subcategories = ko.dependentObservable({
        read: function() {
            var currentCategory = this.category();
            var category = ko.utils.arrayFirst(viewModel.categoryData(), function(data) {
                return data.category() === currentCategory;
            });

            return category ? category.subcategories() : [];

        },
        deferEvaluation: true,
        owner: this
    });
}

var options = {
    items: {
        create: function(options) {
            return new Item(options.data);
        }
    }
}

var viewModel = ko.mapping.fromJS(originalData, options);

ko.applyBindings(viewModel);