Win a copy of Practical SVG this week in the HTML/CSS/JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Understanding Primefaces tree component and creating dynamic tree from database

 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have 3 entities in my JSF application - markets, topics, items which have parent child relationships to each other. I need to display a list in a tree like format so that clicking markets displays the related topic list to each market, clicking topic shows the item list related to each topic. I'm using Primefaces as my web interface so I figured the PF tree component is the right way to go. I looked at the official PF documentation. This only gives static examples and I don't understand how to create a tree dynamically from a database.

My jsf:



The backing bean:




The exception:


The facade for the child node (topics):


So I have a general question about trees and a specific one about how I'm going about this.

Is the above the correct approach where I'm grabbing the tree values using ArrayList objects from the parent and child entities to dynamically create the tree object and its nodes?

Specific to the above exception, the stack overflow error suggests that the application is going into an infinite loop. At the same time the exception shows UNKNOWN SOURCE next to the marketTopNorm (the child node list)? if it's an unknown source why is it being processed? Why does it not give a NullPointerException for example?

Thanks in advance!
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I worked with the RichFaces Tree Control a couple of years ago and it drove me crazy. I wasn't as facile with JSF at the time and the instructions were not only a bit minimalist, but also in "Russian" English, which is harder to understand than Indian English. Russian doesn't have certain grammatical constructs that nuance English expressions, so people who are accustomed to its usages tend to say things that are ambiguous in English.

I haven't worked with the PrimeFaces tree component at all, but at least I now understand the theory better, so I'll cover that and maybe it will give you some clues.

The first thing to understand is that in JSF, the UI Model data objects are all expected to be POJOs. That make it easier, for example, to take an ORM Entity object and use it directly (in some cases) as a UI Model object without having to resort to clumsy intermediaries such as the old DTOs.

However, trees, like tables, have additional context that need to be tracked and managed. For a dataTable, that management is accomplished by use of the JSF model helper (façade) class DataModel, which provides a way to determine which row in the table you clicked in when you selected a commandButton or commandLink (or AJAX action).

Tree controls require something similar, but more complex. Typically the tree control not only has to track possible node selection, but also whether the children of a node are expanded or not and to facilitate just-in-time population of the underlying POJO model so that you don't have to take the immense hit that would come if you needed to assemble the entire model at once (and in the project that I was working with, that model was several megabytes and dozens of records.

In short, clicking on a tree node should fire a server-side event that you can listen for and use to load children and assemble them into the dynamic model before the actual display fetch would occur.

That's the theory. Details, I'm afraid are up to you. I'd have to go back and reread the documentation even for RichFaces and I already have a working app on that platform. It's one of the most complex UI constructs that JSF supports.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hope you're well and thanks for a typically insightful response :) in 'not too sarcastic English' ... great to know trees are so complicated. Easy to take for granted how easy it should be to have a list that simply expands and contracts based on user choice.

Tree controls require something similar, but more complex


My research suggests that 'something similar' could be recursive methods in the POJO which take care of the user functions (click, expand, etc). Before I set about trying to wrote such a method, is it recommended to use a List to populate the tree in this method or should the tree be populated directly from the database?

 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, if the POJO has to know about the mechanisms for expanding/contracting the tree, then they are no longer POJO's, because they now contain specialized UI-specific knowledge and/or functionality. It's the purpose of the Model helper classes to deal with that, leaving the actual data model as pure (POJO) data. The helper classes would handle the database fetches and ensure that any lazy fetching of POJO subtrees was done. The model helpers reference their respective model objects, allowing them to act as façades containing the extra logic (and Controller support data).

The data model should not be a (linear) List, it really should be a tree in the same structure as the displayed tree. Generally, so would the model helper class objects, since they mirror the data tree.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So I'm trying to get my teeth stuck in by adapting a generic PF tree method to be built dynamically from the database. The reason I keep mentioning Lists is because I've seen examples using Lists but mostly because I want to know how I would be able to use methods like getRowData to invoke actions from the dynamic tree model if I'm not going to use underlying lists in the data model?
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, darn it, you made me look at the documentation.

Unfortunately, it's just about in the same league as the RichFaces tree control documentation, minus the Russian-style English.

The PrimeFaces tree seems to be missing certain features. There doesn't seem to be a server-side event defined for tree operations. But possibly that's because in JSF2 you may be able to get the same effect by attaching ajax functions to the tree nodes. If not, that may be why a Google search keeps turning up complaints that the PrimeFaces tree isn't dynamic.

The DefaultTreeNode seems to be the primary model mechanism. It consists of a data object, a List of children (may be empty), a node "key" and various state properties. in fact, it's suspiciously like the RichFaces 3 tree node, except less complex.

The JavaDocs are minimal. Apparently no one bothered to write descriptions or explanations in the comments. As someone who was doing "literate programming" before Knuth coined the term, all I can say is

Since there are not separate data and label values (like the way SelectItem does), I have to hope that either the "rowKey" does that or that the data object's toString() method supplies the displayed value (but that would make it no longer a pure POJO).

It occurred to me yesterday that there's no actual reason why a value model bound to TreeNodes has to be a tree itself, since the TreeNodes have to form a tree anyway. The actual value objects could presumably be in Lists, Arrays, loose objects or all of the above and more.

So my best guess would be that you'd attach a "click" AJAX event to nodes and have the event handler check the clicked node to see if its child list had been populated, and if not (or if stale), then populate it. There are still unanswered questions here, but until some further documentation turns up, that's about all I can determine.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm sorry but you made me look at it too. After trying to learn retrospective English I decided to ignore most of it and go back to basics. No ajax, just good ole Java. I looked at the static example and simply tried to replace the key static fields with dynamic ones:



So that works fine and I'm able to navigate through a tree. What I now need to do is create an action using a commandLink which invokes a getRowData method ONLY when the user clicks the final child node (items) which takes the user to another page to read the selected item. As a reminder the jsf is:



This is a problem because it doesn't distinguish which part of the tree is clicked so a normal getRowData will result in a NoRowAvailable Exception if anything other than the final child node is clicked. I'm thinking I need to use an ajax onClick event handler here but I'm really not sure.

So my best guess would be that you'd attach a "click" AJAX event to nodes and have the event handler check the clicked node to see if its child list had been populated, and if not (or if stale), then populate it


Assuming I use an Ajax click method. Checking if the child node is populated makes sense, but are you saying that the Ajax will be able to process actual rows clicked thereby allow navigation based on the selected child node value?

I tried this:






This doesn't even navigate to any page no matter which node I click??
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I figured out how to do the navigation through ajax:







This navigates regardless of whichever part of the tree is clicked so i'm still trying to figure out how to only fire the navigation if the final child node is selected. I now need to figure out how to fire the event ONLY IF the final child node is selected (and return null otherwise). This probably a conditional statement that invokes the method if the selectednode equals the child node. Looking again at the API and online doesn't give many clues...

I tried:


No Luck!
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm not sure that that action can be properly processed at the stage of the JSF lifecycle that handles the event.

What I did was make my tree nodes render as links so that clicking on them navigated directly from the client. Since I like to use PrettyFaces to help support bookmarkable URLs, I was then able to use the h:outputLink directive to render the links. I haven't had occasion to do anything like that under JSF2, which doesn't need PrettyFaces as much - and might have alternative equivalents - but that way works great for me.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's very helpful to know but how does that work? Returning the nodes as hyperlinks would make all of the nodes as hyperlinks right? How would you distinguish between child and parent nodes so that only child nodes are clickable?

Are you using a Java function to do that? Are you extending the Ajax method?
Do you create a data model and integrate that in the tree constructor?

 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, actually, there's no law that says that only child nodes need to be links, and tree controls often have a separation between the open/close widget and the label that helps with that, since it allows you to make the label a link and still have something to click on to open/close.

But consider a common case where you have a 3-level menu tree of Country, State/Province, City. In most cases, you know that the City nodes are leaf nodes, or at least you can tell that perhaps a State has no City children and thus might be considered as a leaf itself. Or, in the case where all nodes are of the same type, you have nodes-with-children (branches) and nodes-with-no-children (leaves).

I definitely have a UI backing data model. It's where I get the information needed to render the labels etc. from. The links themselves were ordinary outputLinks, so JSF rendered them with sufficient context that PrettyFaces could understand what to do with them (what View to associate and what parameters to pass). I was jumping to different pages, so AJAX didn't apply.

Bear in mind that you have have to come up with something different. What I did was based on RichFaces, and I cannot find equivalent mechanisms in PrimeFaces. They may be there, but I'm not familiar enough with that platform and the docs could stand some improvement.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But consider a common case where you have a 3-level menu tree of Country, State/Province, City.


Well your advice about leaves helped me figure out how to implement my example (which is actually similar to a common case - 2 branches and a eaf):



This is a messy way of doing it. It works as long as there are no duplicate item names, which is why I'd prefer to search for the item Id in the database. Any idea how I can do that?
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmm. Let's step back a minute and re-formulate this in MVC terms.

MVC is a popular paradigm for 2 reasons: First, because it allows multiple mappings. My favorite example is a page with both a table (control) and a pie chart (control) following the same data (model). The second reason is that MVC is based on the concept that a control may be a simple control (for example a textbox), a compound control (combo box) or a container control (for example a panelGrid). A container control can itself contain controls, including other container controls.

Or, lets' re-state that. A control is a sub-view contained within the master View (web page, in your case). So a TreeView control is a container control (sub-view) and, like all views, has a corresponding Model linked by a Controller (provided by JSF). Each node on the tree is itself a sub-View, and maps to a sub-Model. So you can (and should) simplify your thinking by casting it in terms of the simpler Views and Models.

Let's do a crude diagram:


In this diagram, the "+" are subtree open/close widgets. I've used "@" to indicate terminal nodes. So assume that each node has a "+" or "@" widget and a label, which may or may not be a hyperlink. That gives up the following behaviors for each Node sub-view (control):

1. For the sub-subview "+" control, the TreeView's master Controller fires an open/close Node event. Associated with that event may be a user-defined listener where you can populate/update the sub-models for that node brefore the Node's Controller re-renders the Node and its children (if any).

2. For the sub-subview "@" control, the TreeView's master Controller fires an open/close Node event, but we have no children, so we do nothing.

3. For clicks on the label, the labels rendered as hyperlinks, so MVC doesn't apply. Instead, the jump is made to a new View (page). Incidentally, I ended up using outputLinks instead of commandLinks because I noticed that menus tended to spend a lot of idle time and so when people finally clicked on something, the JSF context had often timed out, discarding the necessary context required for a JSF command action. A raw hyperlink, on the other hand, is a non-JSF construct, so there's nothing to time out. With the aid of PrettyFaces, I could parameterize these links (for example http://myhost/mywebapp/location/Queensland/Brisbane") and avoid that problem.

Here's something that may help. I finally ran across what looks to be a useful reference: http://www.primefaces.org/showcase/ui/data/tree/events.xhtml

Note that a single set of AJAX listeners apply to ALL nodes. If I'm not mistaken, the tree's "selection" attribute will indicate which node was actually initiating the event. They also used simple outputText instead of outputLink, but that's proper, depending on how you like things to work. One of the other reasons I was using outputLinks was that my links could be "bookmarked" by clients as "favorites" so that popular items could be directly access via the user's "favorite" link menu.

This takes us back, I think to the issue of making the tree dynamic. If you use the form that the above example uses, it's for a static tree. If PrimeFaces doesn't have direct support for anything more dynamic, you can do it the hard way, which is to add a "binding=" attribute to the p:tree element and construct TreeNodes in Java code when the AJAX listeners fire.


 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So you can (and should) simplify your thinking by casting it in terms of the simpler Views and Models.


Ok so there are 3 sub views (Market, topic, item) mapping to 3 models? If i'm not mistaken, the sub views are the node branches and children. But i'm confused about what the model is. A model represents the data and nothing else, meaning it doesn't depend on the controller or the view. In my case, the JPA persistence class is used to populate a list which populates the treeNode in the managed bean. The MVC paradigm suggests the model should be the JPA class. There are 3 classes for each of the node views. The model for the market entity is:



If this is the model, then I am already using it to dynamically populate the tree from the database. Correct?

If I'm not mistaken, the tree's "selection" attribute will indicate which node was actually initiating the event


Correct and the console message confirms that the selected node correctly returns a String representation

If PrimeFaces doesn't have direct support for anything more dynamic, you can do it the hard way, which is to add a "binding=" attribute to the p:tree element and construct TreeNodes in Java code when the AJAX listeners fire.


By 'more dynamic' do you mean a method which integrates the tree back to the data model? The way I see it, i'm already pulling values from the database dynamically. The problem is that I'm using a list to create the tree. Once the tree is created it loses connection to the data model. I'm guessing the binding attribute would tie the tree directly to the data model so the entity values could be accessed by the TreeNode? Finally, if I'm creating trees manually and customizing the datamodel, doesn't the use of PF become e more redundant? Would it then be much harder to use a plain java tree and plain html?
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There are many more than 3 Models. There are only 3 types of Models for the tree, but an arbitrary number of instances of those types. Each detail item is a sub-model. A "Topic" is a Model (with a name), but it's also (presumably) a container for Item sub-models. Likewise, a Market is a Model, with Topics as sub-models. Each sub-Model has a corresponding sub-View.

I want to correct a common misconception. JPA Models (also known as Persistence Models or Object Models) are NOT the same thing as JSF's GUI Models. A GUI Model contains context needed to for the JSF Controllers to render and to process the View. Since both kinds of Models (JPA and JSF) are POJOs, it's frequently common to use the same object in both roles, but it isn't essential. A classic example being databases that don't support boolean-type columns being mapped to a JSF control with checkboxes. You need a distinct GUI model with boolean properties to intercede for the persistence model object that's using "T/F", "1/0" or whatever as boolean values, since JSF checkboxes [i]demand[/b] boolean Model properties and there's no way in current JSF to provide a Converter to deal with that.

When I said "dynamic", what I meant was that instead of constructing the tree using fixed elements like the example did that you'd define the tree nodes on-demand (and with the possibility that the nodes themselves might even change if the underlying database records were changed/added/deleted). In other words, when you do an expansion click on a node that isn't previously populated, you'd do a pull for its children from the database, construct and add sub-models for that node based on the returned children (if any), and correspondingly construct PrimeFaces treenodes to map 1-to-1 to those sub-model items.

As for doing the whole thing in raw HTML, yes you can, but it's re-inventing a rather tedious wheel. A better idea would be to use one of the existing JavaScript libraries that has a tree control. But neither of those solutions would have a natural integration with JSF.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I want to correct a common misconception. JPA Models (also known as Persistence Models or Object Models) are NOT the same thing as JSF's GUI Modes


Ok so I can assume a number of generic models for each node element on terms of GUI and data, as well as the generic elements which I override on my own JPA classes and backing bean?

When I said "dynamic"


Right, so I'm already creating the tree on demand from the database, which indicates that PF does support dynamic trees. Both data and GUI models seem to be creating the tree view and firing the expand and select events if all I want is a tree that is renders and changes as database values are changed. I tried changing the DB values and it is successfully updated in the tree. The tricky part is if I want a reliable way to do anything OUTSIDE the tree component like use the selectednode to navigate to another page.

I can even do that in a messy way by searching for the string value of the selectednode and navigating to the page corresponding to that value. So can we agree that PF does seem to support at least a basic level of dynamic tree handling (taking your point about not reinventing the wheel through HTML)?

So, the problem SEEMS to be how I can maintain the connection between the data models and the tree so that the selectednode can be related to the entity ID (itemid) in displaying the detail from the selectednode? If we agree that this is my concrete problem, then is a bind attribute achieve that purpose? If I'm missing in my underlying understanding of the tree and JSF please let me know and thanks again!
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, here's another context. A dataTable uses a DataModel as its Model façade. It does this because the DataModel can wrap a POJO model, but adds some useful JSF-specific features, much like the TreeNode does for PrimeFaces trees.

There's one difference, though. A DataModel is a wrapper for multiple sub-model (row) objects and because of how the dataTable control and its internal Controller are designed, there's no need to explicitly define a separate row the way you would have to for a brute-force HTML TABLE with TR and TD tags. Instead, the dataTable takes a prototype row definition (that defines headers, footers, and columns) and internally generates its row sub-views. If the Model changes (adds or removes rows), the dataTable changes the internal collection of row sub-views to match.

As far as I know, however, the PrimeFaces doesn't automatically generate TreeNode objects. So if you change the data model, you'd have to manually add/remove TreeNodes and map them to the corresponding added/removed data model objects.

For navigating to a new page, as I said earlier, I found it easiest to make the displayed nodes render as outputLinks, which are nothing but plain old HTML "A" HREF elements, but civilized by the automatic addition of application context path to the URL where appropriate. Such links don't go through JSF navigation, but simply initiate a new JSF page URL request via an HTTP GET.
 
Jay Tai
Ranch Hand
Posts: 221
Java MySQL Database Netbeans IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, here's another context. A dataTable uses a DataModel as its Model façade. It does this because the DataModel can wrap a POJO model, but adds some useful JSF-specific features, much like the TreeNode does for PrimeFaces trees.


So to confirm TreeNode can wrap a POJO model but adds JSF specific features for Primefaces tree?


As far as I know, however, the PrimeFaces doesn't automatically generate TreeNode objects. So if you change the data model, you'd have to manually add/remove TreeNodes and map them to the corresponding added/removed data model objects.


So are you saying that there may be no automatic way (generic method) in PF which directly 'links' the TreeNode to its data model in the same way that say DataModel is linked to a ListDataModel? In that case, TreeNode has to rely on wrapping a POJO model to manually synch the TreeNode with its data model? Doesn't that imply that you could write an automatic way to generate a TreeNode object in the POJO wrapped by the TreeNode?
 
Tim Holloway
Bartender
Posts: 18423
60
Android Eclipse IDE Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There you're getting out of the theoretical, which is all I am really good at here, and into PrimeFaces specifics. I'm not well-studied enough to be able to say if/how well PrimeFaces TreeNodes actually wrap POJOs. In any event, the TreeNode element is a View component, and Views don't wrap Models. Instead they are bound to Models via their respective Controllers. The DataModel (and SelectItem) classes are Model wrappers that add functions that the Controllers (and application code) can benefit from..

Yes, it's possible to dynamically add View/Controller pairs to newly-added Model objects. The RichFaces Tree control has that ability. Whether PrimeFaces does or not is less certain. A lot of people seem to think not, but I take opinions stated on the Internet with a kilogram of salt. Even when they're correct when stated, the information may be out of date.
 
Hug your destiny! And hug this tiny ad:
the new thread boost feature: great for the advertiser and smooth for the coderanch user
https://coderanch.com/t/674455/Thread-Boost-feature
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!