Recursive templating doesn't work with ko.mapping plugin

149 views
Skip to first unread message

Vin

unread,
Jan 20, 2011, 12:16:18 PM1/20/11
to KnockoutJS
I am trying to do recursive templating on a tree using the mapping
plugin, but I can't get to have it rendered, unless I define separate
templates for each level.

In the following case, I want to reuse the mvvmTreeViewGroupTemplate
for mvvmTreeViewSubGroups as well, but this is not being rendered, is
this a bug or not implemented feature?

<script type="text/x-jquery-tmpl" id="mvvmTreeViewGroupTemplate">
<li>
<span data-bind="text: Title" class="mvvmTreeItemStyle"/></br/>

<ul data-bind='template: {
name: "mvvmTreeViewItemTemplate",
foreach: MvvmTreeItems,
beforeRemove: function(elem) { $
(elem).slideUp() },
afterAdd: function(elem) { $
(elem).hide().slideDown() }
}'>
<ul data-bind='template: {
name: "mvvmTreeViewSubGroupTemplate",
foreach: this.MvvmTreeItemSubGroups,
beforeRemove: function(elem) { $
(elem).slideUp() },
afterAdd: function(elem) { $
(elem).hide().slideDown() }
}'>
</ul>
</ul>
</li>
</script>

<script type="text/x-jquery-tmpl" id="mvvmTreeViewSubGroupTemplate">
<li>
<span data-bind="text: Title" class="mvvmTreeItemStyle"/></br/>

<ul data-bind='template: {
name: "mvvmTreeViewItemTemplate",
foreach: MvvmTreeItems,
beforeRemove: function(elem) { $
(elem).slideUp() },
afterAdd: function(elem) { $
(elem).hide().slideDown() }
}'>
</ul>
</li>
</script>

JSON looks like this,

var data = {
MvvmTreeItemGroups: [
{
Id: 1, Title: 'Group 1',
MvvmTreeItemSubGroups: [{
Id: 1, Title: 'Group 11',
MvvmTreeItems: [{ Id: 'i111', Title: 'Item 111' },
{ Id: 'i112', Title: 'Item 112'}]
},
{
Id: 1, Title: 'Group 121',
MvvmTreeItems: [{ Id: 'i121', Title: 'Item
121' }, { Id: 'i122', Title: 'Item 122'}]

}],
MvvmTreeItems: [{ Id: 'i11', Title: 'Item 11' }, { Id:
'i12', Title: 'Item 12'}]

},
{
Id: 2, Title: 'Group 2',
MvvmTreeItemSubGroups: [{
Id: 1, Title: 'Group 211',
MvvmTreeItems: [{ Id: 'i211', Title: 'Item
211' }, { Id: 'i212', Title: 'Item 212'}]
},
{
Id: 1, Title: 'Group 121',
MvvmTreeItems: [{ Id: 'i121', Title: 'Item
121' }, { Id: 'i122', Title: 'Item 122'}]

}],
MvvmTreeItems: [{ Id: 'i21', Title: 'Item 21' },
{ Id: 'i22', Title: 'Item 22'}]
}]
};

rpn

unread,
Jan 20, 2011, 3:20:01 PM1/20/11
to KnockoutJS
Not sure if this is the only issue, but if you change
"this.MvvmTreeItemSubGroups" to just "MvvmTreeItemSubGroups" in the
binding of the subgroups, then it renders the inner tree items.

Like here: http://jsfiddle.net/rniemeyer/RPAkm/

Hope this helps.

Vin

unread,
Jan 20, 2011, 4:11:44 PM1/20/11
to KnockoutJS
I know, that works.

But that's not recursive, the goal is for the
mvvmTreeViewGroupTemplate to call itself such that there is no
mvvmTreeViewSubGroupTemplate

Thanks for the sample on JSFiddle.

rpn

unread,
Jan 20, 2011, 4:31:13 PM1/20/11
to KnockoutJS
OK- I guess I spent a few minutes getting your code properly working
in JSFiddle and lost track of your original question.

I am not having any luck getting a recursive version to work. Sorry.

fla...@gmail.com

unread,
Jan 23, 2011, 12:30:19 PM1/23/11
to KnockoutJS
Try this: http://jsfiddle.net/nyXWJ/

The only reason your original code didn't work is that your main
template was always trying to evaluate the data item's
MvvmTreeItemSubGroups property, even for the inner items that didn't
have one. This would cause an error. To fix this, I've added the check
"{{if 'MvvmTreeItemSubGroups' in $data}}", and then the template
worked fine recursively.

Alternatively, you could ensure that all your items would have an
MvvmTreeItemSubGroups property, and then the {{if ...}} test wouldn't
be necessary either.

Steve

Vin

unread,
Jan 23, 2011, 8:32:27 PM1/23/11
to KnockoutJS
Agreed, like @mikekidder explains here

it can also be checked like so, {{if $data.MvvmTreeItems }}
didn't know about using the "in" keyword, thanks for pointing out.

For future reference, here's the fiddle for the same -
http://jsfiddle.net/mikekidder/Xs7sy/

Thanks again,
Vin
Reply all
Reply to author
Forward
0 new messages