Reputation: 53
I have developed a tree view that uses knockout to display a hierarchy. I have noticed a weird situation within chrome that happens when I collapse a node in the tree. The text for the node disappears along with the items under it. I figured I had something wrong with my code and then figured out that it works correctly in both IE and firefox. I created the fiddle below that demonstrates the issue with any extra code from my page stripped out. If you expand a node and then collapse it (the plus button does not change to a minus as it would in my full code), the text disappears. Then, you can just click anywhere on the page to get the text to show back up.
The text that disappears has been outlined in red as recommended in a comment and can be seen in the screenshot
I have tested this out on 4 machines and on each one it doesn't work when I use Chrome. Is this a bug in Chrome, or am I doing something wrong? Also, can anybody see any way to work around this issue if it is a bug in Chrome?
console.clear();
var hierarchyNode = function (parent) {
var self = this;
this.name = "Node Name";
this.hasChildren = ko.observable(true);
this.childNodes = ko.observableArray();
this.expanded = ko.observable(false);
};
hierarchyNode.prototype = {
name: null,
hasChildren: null,
childNodes: null,
getChildNodes: function (element, event) {
if (element.hasChildren() === true && element.childNodes().length === 0) {
element.childNodes.push(new hierarchyNode(element));
}
element.expanded(!element.expanded());
}
};
var hierarchyVM = function () {
var self = this;
self.hierarchyNodes = ko.observableArray();
self.selectItem = function () {};
};
var vm = new hierarchyVM();
vm.hierarchyNodes.push(new hierarchyNode(null));
console.log(vm.hierarchyNodes()[0]);
ko.applyBindings(vm);
ul.tree {
list-style-type: none;
padding-left: 10px;
}
.hierarchyNode {border: 1px solid red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="tree" data-bind="template: { name: 'itemTmpl', foreach: $data.hierarchyNodes }"></ul>
<script id="itemTmpl" type="text/html">
<li>
<button data-bind="click: getChildNodes">+</button>
<div data-bind="visible: hasChildren() == false" class="tree-spacer"></div>
<span data-bind="text: name" class="no_selection hierarchyNode"></span>
<ul class="tree" data-bind="template: { name: 'itemTmpl', foreach: $data.childNodes }, visible: expanded"></ul>
</li>
</script>
Upvotes: 5
Views: 836
Reputation: 134571
I was able to fix it by changing the visible binding to use an if
parameter on the template instead. I don't know why this would fix it, but there you go.
<ul data-bind="template: { name: 'itemTmpl', foreach: childNodes, 'if': expanded }"></ul>
This does seem to be a Chrome specific bug because the markup is clearly not being changed for the name element. Just clicking anywhere after collapsing makes it appear. A bug in the renderer perhaps?
Upvotes: 2
Reputation: 63810
I'm hoping for a competing answer, or some help with my own answer, but in the mean time: here's a workaround. There's something off with the display
property of that span
. I've reduced your example quite a bit, could still repro the issue, and was able to "fix" it with setting an explicit display
rule. See this:
var hierarchyNode = function (parent) {
var self = this;
self.name = "Some node";
self.childNodes = ko.observableArray([]);
self.expanded = ko.observable(false);
self.getChildNodes = function (element, event) {
if (self.childNodes().length === 0) {
self.childNodes.push(new hierarchyNode(self));
}
self.expanded(!self.expanded());
}
};
var hierarchyVM = function () {
var self = this;
self.hierarchyNodes = ko.observableArray([new hierarchyNode(null)]);
};
ko.applyBindings(new hierarchyVM());
.node-name { border: 1px solid red; }
/* Workaround: */
.node-name { display: inline-block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul class="tree" data-bind="template: { name: 'itemTmpl', foreach: $data.hierarchyNodes }"></ul>
<script id="itemTmpl" type="text/html">
<li>
<button data-bind="click: getChildNodes">+</button>
<span data-bind="text: name" class="node-name"></span>
<ul data-bind="template: { name: 'itemTmpl', foreach: childNodes }, visible: expanded"></ul>
</li>
</script>
PS. To answer one other part of your question, my guess is that this is indeed a bug in Chrome.
Upvotes: 1