Available in the OSS Version
Tree - KnockoutJS Binding
This sample demonstrates how to bind igTree to hierarchical data managed by KnockoutJS data bindings.
This sample uses CTP (Community Technical Preview) features. The API and behavior may change when these features are released with full support.
Getting data from server...
Category
| Name: | |
| Description: | |
| Product Count: |
Product
| Name: | |
| Quantity per Unit: | |
| Unit Price: | |
| Units in Stock: | |
| Units on Order: | |
| Discontinued |
This sample is designed for a larger screen size.
On mobile, try rotating your screen, view full size, or email to another device.
Note: The Knockout extensions do not work with the ASP.NET MVC Helpers.
Code View
Copy to Clipboard
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <!-- Ignite UI for jQuery Required Combined CSS Files --> <link href="http://cdn-na.infragistics.com/igniteui/2024.2/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" /> <link href="http://cdn-na.infragistics.com/igniteui/2024.2/latest/css/structure/infragistics.css" rel="stylesheet" /> <script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script> <!-- Ignite UI for jQuery Required Combined JavaScript Files --> <script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/infragistics.core.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/infragistics.lob.js"></script> </head> <body> <script src="/js/external/knockout-latest.js" type="text/javascript"></script> <script src="/js/external/knockout.mapping-latest.js" type="text/javascript"></script> <script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/extensions/infragistics.ui.tree.knockout-extensions.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2024.2/latest/js/extensions/infragistics.ui.editors.knockout-extensions.js"></script> <script type="text/javascript"> var viewModel; // Define empty objects for Category and Product to be used when // nothing is to be rendered in the editor controls ViewModel.prototype.categoryEmpty = { CategoryName: "", Description: "", ProductCount: 0 }; ViewModel.prototype.productEmpty = { ProductName: "", QuantityPerUnit: 0.0, UnitPrice: 0.0, UnitsInStock: 0.0, UnitsOnOrder: 0.0, Discontinued: false }; // Creates a ViewModel object function ViewModel(categories) { var self = this; this.data = categories; this.Category = ko.observable(self.categoryEmpty); this.Product = ko.observable(self.productEmpty); this.SetSelected = function (item) { if (item.ProductName != null) { self.Product(item); } else if (item.CategoryName != null) { self.Category(item); self.Product(self.productEmpty); } }; }; $(function () { $(".message").ajaxError(function () { $(this).css("color", "red"); $(this).text("Error getting product categories!"); }); // Get all the Categories and their related Products from the Northwind database $.getJSON("https://www.igniteui.com/api/categories?callback=?", function (data) { viewModel = new ViewModel(ko.mapping.fromJS(data.d.results)); viewModel.Category.subscribe(function (item) { setContainerVisible(item, "#categoryEditorsContainer"); }); viewModel.Product.subscribe(function (item) { setContainerVisible(item, "#productEditorsContainer"); }); ko.applyBindings(viewModel); $(".message").hide(); }, 'json'); }); function setContainerVisible(item, containerSelector) { if (item != null && item.hasOwnProperty("ID")) { $(containerSelector).show(); } else { $(containerSelector).hide(); } } $(function () { $(document).on("igtreeselectionchanged", "#tree", function (evt, ui) { if (ui.newNodes.length > 0) { var parentElement = $("#tree").igTree("parentNode", ui.newNodes[0].element); // Set selected Category to be the category of the selected product if (parentElement) { var parentNode = $("#tree").igTree("nodeFromElement", parentElement); viewModel.SetSelected(parentNode.data); setTimeout(function () { if ($(window).width() < 600) { $("#productEditorsContainer").focus(); } }, 0); } else { setTimeout(function () { if ($(window).width() < 600) { $("#categoryEditorsContainer").focus(); } }, 0); } viewModel.SetSelected(ui.newNodes[0].data); } }); }); </script> <style> .message { color: darkorange; font-weight: bold; } .container { width: 40%; position: relative; float: left; padding: 0px 10px 0px 10px; } #tree { border-right: 1px solid grey; } #categoryEditorsContainer, #productEditorsContainer { display: none; } @media screen and (max-width: 600px) { .container { width: 100%; clear: both; padding-top: 10px; } #tree { border-right: none; border-bottom: 1px solid grey; } } </style> <div><span class="message">Getting data from server...</span></div> <div class="container"> <div id="tree" data-bind="igTree: { dataSource: data, width: '100%', dataSourceType: 'json', singleBranchExpand: true, bindings: { textKey: 'CategoryName', valueKey: 'ID', childDataProperty: 'Products', bindings: { textKey: 'ProductName', valueKey: 'ProductID' } } }"></div> </div> <div class="container"> <div id="categoryEditorsContainer" tabindex="0"> <h4>Category</h4> <table> <colgroup> <col span="1" style="min-width: 30%;" /> <col span="1" style="width: 68%;" /> </colgroup> <tr> <td>Name:</td> <td><div data-bind="igTextEditor: { value: Category().CategoryName, updateMode: 'immediate' }"></div> </td> </tr> <tr> <td>Description:</td> <td><div data-bind="igTextEditor: { value: Category().Description }"></div></td> </tr> <tr> <td>Product Count:</td> <td><div data-bind="igNumericEditor: { value: Category().ProductCount }"></div></td> </tr> </table> </div> <div id="productEditorsContainer" tabindex="1"> <h4>Product</h4> <table> <colgroup> <col span="1" style="min-width: 30%;" /> <col span="1" style="width: 68%;" /> </colgroup> <tr> <td>Name:</td> <td><div data-bind="igTextEditor: { value: Product().ProductName }"></div></td> </tr> <tr> <td>Quantity per Unit:</td> <td><div data-bind="igNumericEditor: { value: Product().QuantityPerUnit }"></div></td> </tr> <tr> <td>Unit Price:</td> <td><div data-bind="igCurrencyEditor: { value: Product().UnitPrice }"></div></td> </tr> <tr> <td>Units in Stock:</td> <td><div data-bind="igNumericEditor: { value: Product().UnitsInStock }"></div></td> </tr> <tr> <td>Units on Order:</td> <td><div data-bind="igNumericEditor: { value: Product().UnitsOnOrder }"></div></td> </tr> <tr> <td>Discontinued</td> <td><input type="checkbox" data-bind="checked: Product().Discontinued"/></td> </tr> </table> </div> </div> </body> </html>