KnockoutJS and treeview/recursion

2,751 views
Skip to first unread message

tod...@gmail.com

unread,
Feb 21, 2013, 10:35:36 AM2/21/13
to knock...@googlegroups.com
I have a site I am working on, and need to build a treeview for some admin functions. KnockoutJS would be a huge help here in terms of editing items and modifying the treeview. That being said, I am not sure how to accomplish it. I am very much a novice KnockoutJS user (but not a new web developer). 

Most of the examples I see of working with Lists and Collections in Knockout seem to take a "foreach" approach to generating the HTML and binding data. Since I am building a treeview (<ul> and <li> objects) what I really need to do is use recursion to build the HTML.

My data objects do have a basic structure including Id, Name and a Children collection which in turn hosts other objects of the same type.

The environment I'm working in is an ASP.NET MVC 4 project, so I don't care much "how" this gets done. I could build the object in code behind using C# (what I'm doing now), but I need a way to markup the HTML so it binds to the ViewModel objects/properties. I am also open to using JavaScript to create the DOM objects, or if I can build the HTML using a foreach loop and KnockOut, all the better. 

I did see some source code in a library that accomplished this, but the control was so "fully featured" that trying to narrow it down to just the basics was overwhelming me.

If anyone has any suggestions, ideas or examples of how to create a very vanilla ul/li markup using KnockOut, I'd be very grateful. Thank you. -Todd

rpn

unread,
Feb 21, 2013, 11:41:18 AM2/21/13
to knock...@googlegroups.com, tod...@gmail.com
Hi Todd-
The template binding is a good way to work with nested objects that have the same structure.  For example,

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


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

Note that I used "$data.items" rather than just "items" to help protect against a child object that does not contain the "items" property.

Hope that helps.

Denys Khanzhiyev

unread,
Feb 21, 2013, 1:18:14 PM2/21/13
to knockoutjs
I have recently made big post about TreeView in knockout. Though it is in Russian

here is automatic translation. There is a link to github at the end.

Google translate makes code unreadable here is original link
http://habrahabr.ru/post/165565/


2013/2/21 rpn <rnie...@gmail.com>

--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

tod...@gmail.com

unread,
Feb 21, 2013, 9:30:41 PM2/21/13
to knock...@googlegroups.com, tod...@gmail.com
Thanks you, this worked perfectly and was a direction I had considered. Very cool. Much easier than I thought :)

motox...@gmail.com

unread,
Mar 6, 2013, 2:58:14 PM3/6/13
to knock...@googlegroups.com, tod...@gmail.com
rpn -

This is great! I have a need to do something similar to your example. My only "concern" with this approach is if "items" doesn't have a sub-array, the HTML renders with an empty UL under the LI. 

I've tried doing (with an array of observableArrays):

    <!-- ko if: $data.items().length > 0 -->
        ...ul code...
    <!-- /ko -->

but I get "Object #<Object> has no method 'items';

Do you know of any way around this?

Todd Davis

unread,
Mar 6, 2013, 3:18:01 PM3/6/13
to motox...@gmail.com, knock...@googlegroups.com
I wonder if you could also add a "visible" tag, and tie to the item count. So something like "visible: children.count > 0"
-Todd
Message has been deleted

Kevin Yeh

unread,
May 10, 2013, 8:44:58 AM5/10/13
to knock...@googlegroups.com, tod...@gmail.com
I don't see the problem you are talking about in your jsFiddle.  However, in implementing a recursive menu, I had problems unless I explicitly tested for the existence of children like this in my template.

<script type="text/html" id="menu-entry">
                <span data-bind="text:description, attr:{'class':$data.type},click: menu_click"></span>
                <div data-bind="if:$data.children">
                    <ul data-bind="foreach:$data.children">
                        <li data-bind="template:'menu-entry'"></li>
                    </ul>
                </div>
</script>


On Thursday, May 9, 2013 9:24:47 PM UTC-4, Matthew wrote:
Ryan,
Brilliant - the demo I was looking for.  I've been struggling with a recursive template problem.  The structure is dictated by a web service and adds a few more objects to the array, but otherwise is similar.  I've put my data into a similar example and get different results!   http://jsfiddle.net/mrfurry/73Vqq/5/  

Is there a bug in Knockout that has problems iterating the object array when there are more data types?
Matthew

rich....@edgecase.co.uk

unread,
May 15, 2013, 10:19:33 AM5/15/13
to knock...@googlegroups.com, tod...@gmail.com

try


<script type="text/html" id="menu-entry">
                <span data-bind="text:description, attr:{'class':$data.type},
click: menu_click"></span>
                <div data-bind="visible:$data.children().length > 0">

                    <ul data-bind="foreach:$data.children">
                        <li data-bind="template:'menu-entry'"></li>
                    </ul>
                </div>
</script>
Reply all
Reply to author
Forward
0 new messages