Reputation: 7525
I am using KnockoutJS on my page and trying to populate the DOM for a JsTree, but the JsTree is not identifying the leaves correctly and applying any changes to the code of the leaves(or folders) that KnockoutJs populates. Is there a way to tell JsTree that there is new data and should re-evaluate everything? Script at beginning of page
$(document).ready(function() {
function treeNode(data) {
var self = this;
self.id = ko.observable(data.ID);
self.name = ko.observable(data.Name);
}
function partsViewModel() {
var self = this;
self.partTypes = ko.observableArray([]);
self.selectedPartType = ko.observable();
self.selectedPartType = ko.observable();
$.getJSON("/PartKO/PartTypes", function(allData) {
var mappedPartTypes = $.map(allData, function(item) { return new treeNode(item); });
self.partTypes(mappedPartTypes);
});
$("#navigation").jstree({
"themes": { "theme": "classic" },
"plugins": ["themes", "html_data"]
});
}
ko.applyBindings(new partsViewModel());
});
HTML
ul id="navigation" class="treeview" data-bind="foreach: partTypes">
<li>
<a href="#" data-bind="text:name"></a>
</li>
</ul>
Upvotes: 2
Views: 2635
Reputation: 8556
You need to call .jstree
after the list is populated, so move the call to the end of the $.getJSON
callback.
Also the navigation
should be a container containing the <ul>
element and not the list itself.
Change partsViewModel
function to:
function partsViewModel() {
var self = this;
self.partTypes = ko.observableArray([]);
self.selectedPartType = ko.observable();
self.selectedPartType = ko.observable();
$.getJSON("/PartKO/PartTypes", function(allData) {
var mappedPartTypes = $.map(allData, function(item) { return new treeNode(item); });
self.partTypes(mappedPartTypes);
$("#navigation").jstree({
"themes": { "theme": "classic" },
"plugins": ["themes", "html_data"]
});
});
}
And your HTML to:
<div id="navigation">
<ul class="treeview" data-bind="foreach: partTypes">
<li>
<a href="#" data-bind="text:name"></a>
</li>
</ul>
</div>
HERE is a simplified example.
Update:
If you want to update the tree everytime the <ul>
is changed you can use Knockout's .afterRender
callback. This will be called after the DOM is updated. You cannot use .subscribe()
because that is called before the DOM changes.
Insert this into partsViewModel
and remove the .jstree
part from .getJSON
callback:
self.redrawTree = function() {
$("#navigation").jstree({
"themes": {
"theme": "classic"
},
"plugins": ["themes", "html_data"]
});
};
And change HTML to:
<div id="navigation">
<ul class="treeview" data-bind="foreach: { data: partTypes, afterRender: redrawTree }">
<li>
<a href="#" data-bind="text:name"></a>
</li>
</ul>
</div>
Upvotes: 5