Skip to content

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Knockout TreeView- A nice binding handler that accepts a dynamic tree of data, and displays a searchable and selectable tree-type list.
* {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
font-family: "Segoe UI", "Helvetica", Arial, sans-serif;
}
.navbar{
margin-bottom:10px;
}
.ko-treeview-container {
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
border: 1px solid #eee;
background-color: white;
border-radius: 3px;
padding-right: 7px;
padding-top: 5px;
}
.ko-treeview-container .navbar {
margin-right: 0px;
}
.ko-treeview-container > .ko-treeview-list {
padding: 0;
margin-left:0px;
}
.ko-treeview-list {
list-style: none;
}
.ko-treeview-listitem {
line-height: 2em;
margin-top: 0px;
}
.ko-treeview-label {
-webkit-transition: all 250ms;
-moz-transition: all 250ms;
-ms-transition: all 250ms;
-o-transition: all 250ms;
cursor: pointer;
display: block;
margin-left: 5px;
width: 100%;
background-color: white;
color: #2980b9;
border-bottom: 1px solid #bdc3c7;
}
.ko-treeview-label:hover {
border-bottom-color: #2980b9;
}
.ko-treeview-cb {
-webkit-transition: all 250ms;
-moz-transition: all 250ms;
-ms-transition: all 250ms;
-o-transition: all 250ms;
float: right;
clear: both;
margin-top: 1em;
margin-left: 5px;
}
.ko-treeview-cb:checked {
margin-top: 1.5em;
}
.ko-treeview-cb:checked + label {
line-height: 50px;
font-weight: bold;
border-bottom-color: #27ae60;
font-size: 1.1em;
color: #27ae60;
}
<!DOCTYPE html>
<html>
<head>
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css" rel="stylesheet" type="text/css" />
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css" />
<link href="treeview.css" rel="stylesheet" type="text/css" />
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
<script src="treeview.js"></script>
<meta charset=utf-8 />
<title>Knockout TreeView</title>
</head>
<body>
<div data-bind="treeView:{title:'Some Title',selected:selectedNodes, data:data}">
</div>
<h4>Selected Nodes</h4>
<ul data-bind="foreach: selectedNodes">
<li data-bind="text: $data"></li>
</ul>
</body>
</html>
ko.bindingHandlers.treeView = {
createNodes: function(rootElement, options){
var rootTmpl = '<script id="ko-treeview-root-tmpl"><div class="navbar"><p class="brand" data-bind="text:$data.title">Title</p><div class="container"><form class="navbar-form pull-right col-sm-4"><div class="input-append"><input class="span4" type="text" placeholder="Search" data-bind="value:$data.search, valueUpdate: \'afterkeydown\'"/><span class="add-on"><i class="icon-search"></i></span></div></form></div></div><ul class="ko-treeview-list" data-bind="template:{foreach:$data.data,name:\'ko-treeview-node-tmpl\'}"></ul></script>';
var nodeTmpl = '<script id="ko-treeview-node-tmpl"><li class="ko-treeview-listitem"><div data-bind="template:{name:\'ko-treeview-item-tmpl\',data:$data}"></div><ul class="ko-treeview-list" data-bind="template:{name:\'ko-treeview-node-tmpl\',foreach:$data[$root.childNode]}"></div></li></script>';
var itemTmpl ='<script id="ko-treeview-item-tmpl"><div data-bind="visible:$data[$root.label].indexOf($root.search()) > -1"><input type="checkbox" class="ko-treeview-cb" data-bind="checked: $root.selected, attr:{value:$data[$root.label], id:$data[$root.label]}" /><label class="ko-treeview-label" data-bind="text:$data[$root.label], attr:{for:$data[$root.label]}"></label></div></script>'
//append templates
document.body.insertAdjacentHTML('beforeend', rootTmpl);
document.body.insertAdjacentHTML('beforeend', nodeTmpl);
document.body.insertAdjacentHTML('beforeend', itemTmpl);
//apply first binding
ko.applyBindingsToNode(rootElement, {template:{name:"ko-treeview-root-tmpl"}},options);
},
init: function(element, valueAccessor) {
//style element
element.className = "ko-treeview-container";
//extend options with search
var options = valueAccessor();
options.search = ko.observable("");
//set default data values
if(!options.label) options.label = 'id';
if(!options.childNode) options.childNode = 'children';
//create the tree
ko.bindingHandlers.treeView.createNodes(element,options);
valueAccessor().data.subscribe(function(){
ko.bindingHandlers.treeView.createNodes(element,options);
});
//let this handler control its descendants.
return { controlsDescendantBindings: true };
}
};
function vm(){
this.selectedNodes = ko.observableArray([]);
this.data = ko.observableArray([
{
id:"Level 1",
children:[
{id:"Level 1-1",children:[
{id:"Level 1-1-1",children:[
{id:"Level 1-1-1-1"}
]}
]},
{id:"Level 1-2"},
]
},
{
id:"Level 2",
children:[
{id:"Level 2-1",children:[
{id:"Level 2-1-1"}
]},
{id:"Level 2-2"},
]
},
]);
}
var myVM = new vm();
ko.applyBindings(myVM);
@bringking
Owner
@jotosmurf

@bringking Very nice! Is it possible to give the data a more friendly title attribute along with the id?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.