Search code examples
javascripttemplatesknockout.jsmultidimensional-arrayknockout-templating

Nested templates


I have the following code:

function Session(name, index) {
    this.Messages = [];
    this.Name = name;
    this.Index = index;
}

var vm = {};
vm.Sessions = ko.observableArray([new Session("Foo", 0), new Session("Bar", 1)]);

ko.applyBindings();

vm.Sessions()[0].Messages.push("Hello foo");

Along this view:

<div data-bind="template: {name: 'TopTemplate', foreach: Sessions}">
</div>
<script type="text/html" id="TopTemplate">
    <p>
        ${$data.Name}
    <ul data-bind="template: {name: 'NestedTemplate', foreach: Sessions[${$data.Index}]}"></ul>
    </p>
</script>
<script type="text/html" id="NestedTemplate">
    <li>
    ${$data}
    </li>
</script>

As you can see there is an object with the containing array. So I make the observable array of sessions and it becomes observable including the internal properties. What I want here is to display nested 'repeaters'.

Yesterday I somehow suceeded to execute this script. And what is interesting without showing property name, i.e. Sessions[${$data.Index}].Messages. Unfortunately, I deleted that test script.

Now I've tried to recreate and it doesn't work.

PS. The thing is I don't want to make it work witout showing the relevant property. I just want to make work the nested template.


Solution

  • This seems closer to what you want to accomplish:

    <ul data-bind="template: {name: 'TopTemplate' , foreach: Sessions}"></ul> 
    <script type="text/html" id="TopTemplate">
        <li >    
            <p>${name}</p>
            <ul data-bind=" template: {name:  'NestedTemplate' , foreach: $data} " style="list-style-type:circle;margin-left:15px">
            </ul>
        </li> 
    
    </script>
    <script type="text/html" id="NestedTemplate">         
    {{each(prop, val) $data}}
        {{if $.isArray( val ) }}
            <li>
                <b>${prop}</b>
                <ul  style="list-style-type:square;margin-left:15px" >  
            {{each(index, arrayVal) val}}
                {{each(i, mVal) arrayVal }}
                    <li> 
                        <b>${i}</b>  ${mVal}
                    </li>
                {{/each}}
            {{/each}}
        {{else}}
        <li><b>${prop}</b> : ${val}</li>
        {{/if}}
    {{/each}}     
    </script>
    

    And code:

    var viewModel = {
        Sessions : ko.observableArray([
            {name:"foo",index: 0, messages:[{body:"Hello foo 1"},{body:"Hello foo 2"}]},
            {name:"bar",index: 1, messages:[{body:"Hello foo 3"},{body:"Hello foo 4"}]}
        ])
    };
    
    // ko magic...
    ko.applyBindings(viewModel);
    

    See also this fiddle