Search plugin - show_only_matches = true: How to expand children of matched nodes?

2,558 views
Skip to first unread message

Yves

unread,
Sep 25, 2014, 9:04:49 AM9/25/14
to jst...@googlegroups.com
Hi there.

I use the search plugin together with the show_only_matches option set to true with jsTree 3.0.4. My problem is that I would like to expand the children of the matched nodes which seems not to work or does it?

For the problem illustration, assume the following tree:




















With show_only_matches option set to false a user is able to search for "Google" and then expand its children. So the expand button for the Google tree node works.






























Now, with show_only_matches option set to true a user is able to search for "Google" but is unable to expand its children. (When I click on the expand triangle next to the node nothing happens.)









I have a tree of 200 top nodes with sometimes having 5 levels. Users do not know individual leaf nodes when searching but rather remember a node name on a middle tree level. After they have found such a node in the middle (like the "Google" node) they want to expand its children to the leafs as the interesting information is contained in the leaf nodes.

Maybe this works already and I am just doing it wrong?

Ivan Bozhanov

unread,
Sep 25, 2014, 10:30:01 AM9/25/14
to jst...@googlegroups.com
No, this will not work - there is no way to configure this. Show only matches will do exactly that - show only matches. This may be improved in the future, but it has a few hidden problems - like nested matches, and what should be shown and what not.

Best regards,
Ivan

Yves

unread,
Sep 25, 2014, 11:15:09 AM9/25/14
to jst...@googlegroups.com
Hi Ivan,

thank you for the quick answer.

Nevertheless I hope could demonstrate a use case where it would make sense (from a usability point of view) to have such a feature.

Best,
Yves

Ivan Bozhanov

unread,
Sep 25, 2014, 11:59:42 AM9/25/14
to jst...@googlegroups.com
I see how it can be useful - thanks for the idea, unfortunately I cannot see a way to properly configure this, without creating more problems than solutions. I will give it some thought, please share any other ideas.

Best regards,
Ivan

Yves

unread,
Sep 25, 2014, 6:59:48 PM9/25/14
to jst...@googlegroups.com
I looked at the search plugin's code and fiddled a bit with it. I could not come up with a immediate, perfect solution, but I ended up with this change:

if(this.settings.search.show_only_matches) {
this.element
.on("search.jstree", function (e, data) {
if(data.nodes.length) {
var matchingNodes = data.nodes; // change
$(this).find(".jstree-node").hide().filter('.jstree-last').filter(function() { return this.nextSibling; }).removeClass('jstree-last');
data.nodes.parentsUntil(".jstree").addBack().show()
.filter(".jstree-children").each(function () { $(this).children(".jstree-node:visible").eq(-1).addClass("jstree-last"); });
// nodes need to be in an expanded state
matchingNodes.find(".jstree-node").show(); // change
}
})
.on("clear_search.jstree", function (e, data) {
if(data.nodes.length) {
$(this).find(".jstree-node").css("display","").filter('.jstree-last').filter(function() { return this.nextSibling; }).removeClass('jstree-last');
}
});
}

The idea is to do the node hiding as before. After that, starting from the found nodes again, find all jstree-node and show them as well.

The above small code change only works when all nodes are fully expanded in the tree. Multiple clicks on the expand/collapse button also undo the above change again. I still understand the code too little to make that work properly.

Anyway, doing it like this shows the "problem" with nested search result nodes (which I believe would not be such a big problem). The above code change would result as in the following example:























Whereas without the above code change it looks like this:















I think the above behaviour (my hack) would be already an acceptable result from my point of view.

Of course, optimally only jstree-node(s) would be un-hided that have no siblings which are already included in the search result. So we would not see the nodes "Yahoo", "Youtube", and "Orkut", but we would see "Facebook", "Twitter", "Node 11" through "Node 15".

Something like the above would be my approach.

Best,
Yves

Ivan Bozhanov

unread,
Sep 26, 2014, 2:24:16 AM9/26/14
to jst...@googlegroups.com
I see your point (btw if you make any changes - use the latest from github - it will be easier to integrate). You can really build off from this code you shared - that is great. A few points though:
1) You can package this as your own plugin extending the search plugin - it will trivial and it will be simple to turn on / off
2) Make sure you reset the jstree-last class (there is a visual glitch in the screenshots above).

Now to the problem: Imagine a structure where there is one root node and 1000+ nodes at the second level, and from there it is a deep structure. If the root node itself is a match that will render show_only matches completely useless. That is my main concern.

There are a few ways to fix this - none of which - optimal:
1) I can show the children only when the user voluntarily opens a node, but that would mean that in your example if you want to see Youtube, you'd have to close and open Google, which is not very intuitive
2) I can only show children for the "deepest" results, but that is kind of a half solution
3) There can be a visual element which "shows all children" (maybe next to the open/close arrow), the problem with that is to make it intuitive, and on a side note - it will be a decent amount of work (which is no problem at all of course)

Any thoughts?

Cheers,
Ivan

Yves

unread,
Sep 26, 2014, 4:41:05 PM9/26/14
to jst...@googlegroups.com
Hi Ivan

 
I see your point (btw if you make any changes - use the latest from github - it will be easier to integrate). You can really build off from this code you shared - that is great. A few points though:
1) You can package this as your own plugin extending the search plugin - it will trivial and it will be simple to turn on / off
2) Make sure you reset the jstree-last class (there is a visual glitch in the screenshots above).

Thanks for the hints.

As it looks now, it boils down to think up some fancy tree traversal jQuery for just unhiding the nodes I want.

I am just guessing here: Another option might be to work with your "model" directly. Iterate over all model nodes and filter those out which are not of interest and then take the remaining nodes and render them as <ul> <li> tree.

Mmmh, as I think about that, I probably could just use your API $.jstree.defaults.search.search_callback and implement a function to filter for my nodes of interest.
 
Now to the problem: Imagine a structure where there is one root node and 1000+ nodes at the second level, and from there it is a deep structure. If the root node itself is a match that will render show_only matches completely useless. That is my main concern.

Yes, I agree. 

However, if a user's search string matches the root node (as in your example) that possibly means that s/he would have to navigate the tree anyway to find what s/he is looking for because s/he does not know the lower level nodes of interest. (Well that would be my assumption)  
 
As we do not really know about a user's intention it would make sense to keep the show_only_matches as it is right now. But there should be some possibility for those user who then like to see (expand) the direct children of a matched node.

There are a few ways to fix this - none of which - optimal:
1) I can show the children only when the user voluntarily opens a node, but that would mean that in your example if you want to see Youtube, you'd have to close and open Google, which is not very intuitive

Yup, that would be a bad user experience. It would only make sense if the result tree would show the matched nodes in an closed (not expanded) state, so that the user can click on the triangle of a matched node to expand its direct children.
 
2) I can only show children for the "deepest" results, but that is kind of a half solution

Although tempting, it would possibly confuse the users. In my example I would see all the children of the guava node but what when I also want to see the children of the Google node? So no, it would not work.
 
3) There can be a visual element which "shows all children" (maybe next to the open/close arrow), the problem with that is to make it intuitive, and on a side note - it will be a decent amount of work (which is no problem at all of course)

I think that the intuitive solution would be to stick with the open/close arrow and not to add an additional special visual element. As I described in 1) each matched node would show the closed arrow, then "on click" it would open and display that node's children.  Could that work?
 
Cheers,
Yves

Ivan Bozhanov

unread,
Sep 27, 2014, 3:20:54 AM9/27/14
to jst...@googlegroups.com
I will see what I can do.
As you said - I will probably add a setting, which although the nested matches are shown, would always render a "closed" arrow next to the node, and on open would show all children, the problem is with closing then - should a close really hide the children, or let them be filtered again. Ideas?

Best regards,
Ivan

Yves

unread,
Sep 27, 2014, 10:22:13 AM9/27/14
to jst...@googlegroups.com
Hi Ivan,

I will see what I can do.

Great! Thank you! 
 
As you said - I will probably add a setting, which although the nested matches are shown, would always render a "closed" arrow next to the node, and on open would show all children, the problem is with closing then - should a close really hide the children, or let them be filtered again. Ideas?

I think that the closing function should just hide them again. If they would be filtered again I assume a user could not open those nodes again. That would be puzzling.

After giving it some thought the entire subtree starting from a matched node should be available and not only the immediate direct children of a matched node (not sure if you see it also this way).
My reasoning for this behaviour is as following: Assuming a large, deeply nested tree a user first wants to narrow down his/her search to a few matched nodes. Possibly those matched nodes are just some sort of grouping / category (things that a user might remember or are inherently known to them like an organisation / team name) and then a user would want to drill down from there to find the actual nodes of interest. Having the ability to drill down further should be possible down to the leaf nodes.

Having played around with the jQuery Traversal functions trying to filter out some <li> elements but keeping some others is not easy (or at least for me). And I'm not even sure if jQuery is really the best way to go about it.

Anyway, I appreciate your efforts
Best,
Yves
Reply all
Reply to author
Forward
0 new messages