There is no OOB tree control in the UI Toolkit, so a tree is a small custom coach view. Two quick routes:
1. Custom coach view with a recursive template - bind a list of nodes { label, children[] } and render nested <ul>; a click toggles the child list. About 40 lines, no library:
// coach view "Tree": binding = list of Node {label, id, children (list of Node)}
// load handler
var root = this.context.element, me = this;
function render(nodes, parent) {
var ul = document.createElement("ul"); parent.appendChild(ul);
nodes.forEach(function (n) {
var li = document.createElement("li"), span = document.createElement("span");
span.textContent = (n.children && n.children.length ? "▸ " : "• ") + n.label; li.appendChild(span);
span.onclick = function () { me.context.trigger(function(){}, { id: n.id }); var c = li.querySelector("ul"); if (c) c.style.display = c.style.display == "none" ? "" : "none"; };
if (n.children && n.children.length) render(n.children, li);
ul.appendChild(li);
});
}
render(this.context.binding.get("value").items || this.context.binding.get("value"), root);2. Library-based: add bootstrap-treeview (Bootstrap 3 is already on the coach page) or jstree as managed web assets and feed them the same node list; you get search, checkboxes and lazy loading for free. Fetch levels on demand with an Ajax service (a service flow called from the view) when the data comes from a database.
On the data side, flat SQL results (parent id / child id) are turned into the nested list in a server script before the coach:
var byId = {}; tw.local.rows.forEach(function (r) { byId[r.id] = { id: r.id, label: r.name, children: [] }; });
var roots = []; tw.local.rows.forEach(function (r) { (r.parentId && byId[r.parentId] ? byId[r.parentId].children : roots).push(byId[r.id]); });
tw.local.tree = roots;References