Mapping a n-level deep tree

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

by zoldello

HTML

<script src="https://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<script src="https://rawgithub.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.debug.js"></script>
<ul data-bind="template: 'itemTmpl'"></ul>

<script id="itemTmpl" type="text/html">
    <li>
        <span data-bind="text: name"></span>
        {{if $data.parent}} (my parent is: <span data-bind="text: parent().name()"></span>) {{/if}}
        <a href data-bind="click: function() { viewModel.addChild($data); }"> Add Child </a></li>
    
    <ul data-bind="template: { name: 'itemTmpl', foreach: children }"></ul>      
</script>

CSS

ul { margin-left: 15px; }
a { font-size: .6em; }

JavaScript

var data = {
    name: "root",
    children: [
        {
        name: "1",
        children: [
            {
            name: "1.1"},
        {
            name: "1.2",
            children: [
                {
                name: "1.2.1"},
            {
                name: "1.2.2"}
            ]}
        ]},
    {
        name: "2"}
    ]
};


function RowModel(data, parent) {
    this.name = ko.observable(data.name);
    this.parent = ko.observable(parent);
    this.children = ko.observableArray([]);
    if (data.children) {
        ko.utils.arrayForEach(data.children, function(child) {
            this.children.push(new RowModel(child, this));
        }.bind(this));;
    }
}

viewModel = new RowModel(data, null);

viewModel.addChild = function(parent) {
    parent.children = parent.children || ko.observableArray([]);
    parent.children.push(new RowModel({
        name: parent.name() + ".x"
    }, parent));
}

ko.applyBindings(viewModel);