knockout.js - Knockout recursive template selective binding -
in example, i've got nested template display tree-view indented output, rendered html on leaf nodes not expect. how leaf nodes render expected html , not contain child container div?
if put if binding outside template binding, javascript error:
uncaught error: multiple bindings (if , template) trying control descendant bindings of same element. cannot use these bindings on same element.
note: using if binding comment <!-- ko if: children().length > 0 -->
work remove unwanted element, resulting html riddled comments , i'd prefer keep clean have potentially hundreds of leaf nodes.
i've tried using 2 templates, 1 container , 1 without, , putting in condition name, template rendered nodetempl: data-bind="template: { name: (children().length > 0) ? 'nodetempl' : 'leaftempl', foreach: children }"
i guess want apply different template based on state of child it's processing.
a leaf node rendering this
<div> <div data-bind="text: name">node 1-1-1</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div>
but want render this:
<div> <div data-bind="text: name">node 1-1-1</div> </div>
here's setup:
html
<style type="text/css"> .indent-1 { margin-left: 20px; } </style> <script id="nodetempl" type="text/html"> <div> <div data-bind="text: name"></div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div> </script> <div data-bind="template: { name: 'nodetempl', foreach: children }"></div>
script
var node = function (config) { var self = this; self.name = ko.observable(config.name); self.children = ko.observablearray([]); if ($.isarray(config.children)) { (var = 0; < config.children.length; i++) { self.children.push(new node(config.children[i])); } } }; ko.applybindings(new node( { name: 'root', children: [ { name: 'node1', children: [{name: 'node 1-1', children: [{name: 'node 1-1-1'}]},{name: 'node 1-2'}]}, {name: 'node2',children: [{name: 'node 2-1'},{name: 'node 2-2'}]}, {name: 'node3'}, ] } ));
output
<div data-bind="template: { name: 'nodetempl', foreach: children }"> <div> <div data-bind="text: name">node1</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"> <div> <div data-bind="text: name">node 1-1</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"> <div> <div data-bind="text: name">node 1-1-1</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div> </div> </div> <div> <div data-bind="text: name">node 1-2</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div> </div> </div> <div> <div data-bind="text: name">node2</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"> <div> <div data-bind="text: name">node 2-1</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div> <div> <div data-bind="text: name">node 2-2</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div> </div> </div> <div> <div data-bind="text: name">node3</div> <div class="indent-1" data-bind="template: {if: children().length > 0, name: 'nodetempl', foreach: children }"></div> </div> </div>
you're on right track suggesting need 2 templates. template name
parameter can function returns template name each item in array.
you can create function this:
function nodetemplate(node) { return node.children().length > 0 ? 'nodetempl' : 'nodeleaftempl'; }
and change view this:
<script id="nodetempl" type="text/html"> <div> <div data-bind="text: name"></div> <div class="indent-1" data-bind="template: {name: nodetemplate, foreach: children }"></div> </div> </script> <script id="nodeleaftempl" type="text/html"> <div> <div data-bind="text: name"></div> </div> </script> <div data-bind="template: { name: nodetemplate, foreach: children }"></div>
Comments
Post a Comment