Hierarchy Tree
by WizKid81
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<ul data-bind="template: { name: 'itemTmpl', foreach: $data.hierarchyNodes }"></ul>
<script id="itemTmpl" type="text/html">
<li><button class = "tree-toggle"
data-bind = "click: getChildNodes, text: expandText, visible: hasChildren" > + </button>
<div data-bind="visible: hasChildren == false" class = "tree-spacer"></div>
<span data-bind = "text: name"> </span > <ul data-bind = "template: { name: 'itemTmpl', foreach: $data.childNodes }, visible: expanded" > </ul> </li>
</script>
CSS
ul {
list-style-type: none;
}
.tree-spacer {
display:inline-block;
height:19px;
line-height:19px;
width:21px;
text-decoration:none;
text-align:center;
}
.tree-toggle {
-moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
-webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
box-shadow:inset 0px 1px 0px 0px #ffffff;
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #f9f9f9), color-stop(1, #e9e9e9));
background:-moz-linear-gradient(center top, #f9f9f9 5%, #e9e9e9 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e9e9e9');
background-color:#f9f9f9;
-webkit-border-top-left-radius:0px;
-moz-border-radius-topleft:0px;
border-top-left-radius:0px;
-webkit-border-top-right-radius:0px;
-moz-border-radius-topright:0px;
border-top-right-radius:0px;
-webkit-border-bottom-right-radius:0px;
-moz-border-radius-bottomright:0px;
border-bottom-right-radius:0px;
-webkit-border-bottom-left-radius:0px;
-moz-border-radius-bottomleft:0px;
border-bottom-left-radius:0px;
text-indent:0px;
border:1px solid #dcdcdc;
display:inline-block;
color:#666666;
font-family:Arial;
font-size:15px;
font-weight:bold;
font-style:normal;
height:19px;
line-height:19px;
width:21px;
text-decoration:none;
text-align:center;
text-shadow:1px 1px 0px #ffffff;
}
.tree-toggle:hover {
background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #e9e9e9), color-stop(1, #f9f9f9));
background:-moz-linear-gradient(center top, #e9e9e9 5%, #f9f9f9 100%);
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e9e9e9', endColorstr='#f9f9f9');
background-color:#e9e9e9;
}
.tree-toggle:active {
position:relative;
top:1px;
}
JavaScript
console.clear();
var id = 20;
//Testing function just to create dummy test child
function getTestChild(parent) {
var child = new hierarchyNode();
child.parent_id = parent.id_field;
child.id_field = id;
id = id + 1;
child.name = "Child number " + child.id_field;
child.hasChildren = false;
return child;
}
var hierarchyNode = function (data) {
getObservableArray = function (childNodes) {
var returnArray = ko.observableArray();
$(childNodes).each(function (index, element) {
var hierarchyItem = new hierarchyNode(element);
returnArray.push(hierarchyItem);
})
return returnArray;
}
this.id_field = (data === null || data === undefined || typeof data.ID_Field === "undefined") ? undefined : data.ID_Field;
this.parent_id = (data === null || data === undefined || typeof data.Parent_ID === "undefined") ? undefined : data.Parent_ID;
this.name = (data === null || data === undefined || typeof data.Name === "undefined") ? undefined : data.Name;
this.hasChildren = (data === null || data === undefined || typeof data.HasChildren === "undefined") ? false : data.HasChildren == 1 ? true : false;
this.childNodes = (data === null || data === undefined || typeof data.childNodes === "undefined") ? ko.observableArray() : getObservableArray(data.childNodes);
this.expanded = ko.observable(false);
this.expandText = ko.computed(function () {
if (this.expanded() == true) {
return "-";
} else {
return "+"
}
}, this)
}
hierarchyNode.prototype = {
id_field: null,
parent_id: null,
name: null,
hasChildren: null,
childNodes: null,
populateChildren: function (nodeArray) {
if (this.hasChildren == true && this.childNodes().length == 0) {
var self = this;
$(nodeArray).each(function (index, element) {
var hierarchyItem = new hierarchyNode(element);
...