Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive template with knockout js

Is it possible to create a recursive template only with knockout js?

I have a knockout object:

function FormElementNode(children, text, value) {
   var self = this;
   self.children = ko.observableArray(children);
   self.text = ko.observable(text);
   self.value = ko.observable(value);
}   

children is an array of FormElementNode.

I want to draw it and it's children recursively in a hierarchy list nodes:

<ul>
   <li>Parent text value:
      Children: 
      <ul>
         <li>Child1 text value</li>
         <li>Child2 text value</li>
   </li>

Thanks!

like image 968
bentzy Avatar asked Mar 20 '13 13:03

bentzy


3 Answers

Yes KnockOut supports recursive templates so you can reference and render the same template inside the template.

An example html in your case would look like this:

<script id="formElementNodeTemplate" type="text/html">
<ul>
    <li>Parent <span data-bind="text: text"></span> 
               <span data-bind="text: value"></span>
        <br/>
        Children:
        <!-- ko template: { name: 'formElementNodeTemplate',  
                            foreach: children } -->
        <!-- /ko -->        
     </li>
   </ul>
</script>    

<div data-bind="template: { name: 'formElementNodeTemplate', data: $data }">
</div>

Demo JSFiddle.

like image 196
nemesv Avatar answered Nov 15 '22 14:11

nemesv


I think, I have a little better solution with no tree root (or I guess multiple tree roots). Please take a look:

http://jsfiddle.net/nonsense66/Bzekr/

Template:

<script id="treeElement" type="text/html">
    <li>
        <span data-bind="text: name"></span>
        <ul data-bind="template: { name: 'treeElement', foreach: children }">
        </ul>
     </li>
</script>    

<ul data-bind="template: { name: 'treeElement', foreach: $data.treeRoot }"></ul>

Javascript:

var viewModel = {
    treeRoot: ko.observableArray()
};

var TreeElement = function(name, children) {
   var self = this;
   self.children = ko.observableArray(children);
   self.name = ko.observable(name);
}

var tree = [
    new TreeElement("Russia", [
        new TreeElement("Moscow")
    ]),
    new TreeElement("United States", 
    [
        new TreeElement("New York", [ 
            new TreeElement("Harlem"),
            new TreeElement("Central Park")
        ]) 
    ])
];

viewModel.treeRoot(tree);

ko.applyBindings(viewModel);

Hope it helps!

like image 25
Andrei Avatar answered Nov 15 '22 14:11

Andrei


This post was a great help to me. I am always finding new ways to use knockout. I just wanted to add one useful modification which is doing exactly what nemesv proposed only using the ko.mapping plugin.

//Nested javascript object:
var formElementNode = {
    children: [{
        children: [],
        text: 'Child1',
        value: 'Value1'
    }, {
        children: [{
            children: [{
                children: [],
                text: 'Child2.1.1',
                value: 'Value2.1.1'
            }],
            text: 'Child2.1',
            value: 'Value2.1'
        }],
        text: 'Child2',
        value: 'Value2'
    }, {
        children: [],
        text: 'Child3',
            value: 'Value3'
    }],
    text: 'Main',
    value: 'MainValue'
};

//Use ko.mapping to generate viewModel:
var viewModel = ko.mapping.fromJS(formElementNode);
ko.applyBindings(viewModel);

As demonstrated in this jsFiddle.

like image 7
Bradley Trager Avatar answered Nov 15 '22 12:11

Bradley Trager