Primefaces tree - selection not updated in <p:layout /> with <ui:include/>
I'm experimenting using a navigation tree with a <p:layout />
and an <ui:include />
, which I want to dynamically update the <ui:include />
when I click on a tree node.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.prime.com.tr/ui">
<f:view contentType="text/html">
<h:head></h:head>
<h:body>
<p:layout fullPage="true">
<p:layoutUnit position="left" width="200" resizable="true" collapsible="true">
<h:form>
<p:tree expanded="true" nodeSelectListener="#{menutree.onTreeNodeClicked}" id="tree"
value="#{menutree.menuTree}" var="node" update="test,tree"
selection="#{menutree.selectedNode}" selectionMode="single">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
</h:form>
</p:layoutUnit>
<p:layoutUnit position="center" resizable="true" collapsible="false">
<h:panelGroup id="test" layout="block">
<ui:include src="${menutree.selectedNode.name}.xhtml" />
</h:panelGroup>
</p:layoutUnit>
</p:layout>
</h:body>
</f:view>
</html>
The backing bean looks like this:
@SessionScoped
public class MenuTreeBean implements Serializable
{
private final Log logger = LogFactory.getLog(getClass());
private final TreeNode root;
private TreeNode selectedNode;
public MenuTreeBean()
{
root = new DefaultTreeNode("root", null);
CustomTreeNode aaRoot = new CustomTreeNode("welcome", "Widgets", root);
new CustomTreeNode("1", "Editor", aaRoot);
new CustomTreeNode("2", "Calendar", aaRoot);
setSelectedNode(aaRoot);
}
public TreeNode getMenuTree()
{
return root;
}
public TreeNode getSelectedNode()
{
logger.info("Selected: " + selectedNode);
return selectedNode;
}
public void setSelectedNode(TreeNode selectedNode)
{
logger.info("Selected: " + selectedNode);
this.selectedNode = selectedNode;
}
public void onTreeNodeClicked(NodeSelectEvent e)
{
logger.info("Clicked: " + e.getTreeNode());
selectedNode = e.getTreeNode();
}
}
Correspondingly, there are few more little pages, which contain nothing more than a Primefaces widget - or simply HTML.
This gives such layout in the web browser:
------------------------------------
| Widget | |
| Editor | |
| Calendar | |
| | |
| | |
| | |
| | |
| | |
| | |
------------------------------------
The problem I have is
- when I click on the Editor node above, it gets selected and highlighted, and the
<ui:include />
loads the page/chunk I requested - when I click on the Calendar node above, it gets selected and highlighted, and the
<ui:include />
loads the page/chunk I requested - when I click back on the Editor node above, it did not get selected, but the
<ui:include />
still loads the page/chunk I requested; the Calendar node was still highlighted
If I turn off the update attribute at <p:tree />
, tree node selection and highlight is working as expected; except I miss the dynamic <ui:include />
which I needed.
As for the logging traces above, Widgets is set to be selected initially. Then, when I clicked Editor, the sequence of the methods are
2011/05/24 23:06:25 com.foo.bar.MenuTreeBean getSelectedNode
INFO: Selected: Widgets
2011/05/24 23:06:25 com.foo.bar.MenuTreeBean getSelectedNode
INFO: Selected: Widgets
2011/05/24 23:06:25 com.foo.bar.MenuTreeBean setSelectedNode
INFO: Selected: Editor
2011/05/24 23:06:25 com.foo.bar.MenuTreeBean onTreeNodeClicked
INFO: Clicked: Editor
2011/05/24 23:06:25 com.foo.bar.MenuTreeBean getSelectedNode
INFO: Selected: Editor
But when I clicked Calendar, the sequence became
2011/05/24 23:07:15 com.foo.bar.MenuTreeBean getSelectedNode
INFO: Selected: Editor
2011/05/24 23:07:15 com.foo.bar.MenuTreeBean getSelectedNode
INFO: Selected: Editor
2011/05/24 23:07:15 com.foo.bar.MenuTreeBean setSelectedNode
INFO: Selected: Editor
2011/05/24 23:07:15 com.foo.bar.MenuTreeBean onTreeNodeClicked
INFO: Clicked: Calendar
2011/05/24 23:07:15 com.foo.bar.MenuTreeBean getSelectedNode
INFO: Selected开发者_Python百科: Calendar
I wonder if I miss anything out so that when I click the tree nodes, the <ui:include />
will load, and the tree node gets highlighted?
Thanks in advance.
I can understand what you are trying to do but I don't necessarily think this is the best approach.
Rather than dynamically changing the src
attribute of a <ui:include
tag you should look into a master template page that all child pages will inherit their base content from.
In your template page you can define a layoutUnit as such:
<p:layoutUnit position="center" scrollable="true">
<ui:insert name="content">
<!-- content would go here -->
</ui:insert>
</p:layoutUnit>
Then in your child pages you would specify a composition tag.
<ui:composition template="/WEB-INF/templates/master.xhtml">
Now your tree nodes rather than dynamically update a src attribute can just redirect to the appropriate URL and your tree node and master page content will load appropriately.
I agree with maple_shaft that you should be using a template for this. However if you must stick with this look at the update attribute of the p:tree element. There you specify an ID of an element to update, which can be your ui:include element since that is a UIComponent.
In my application I am also using a p:tree for navigation, but I prefer to force a redirect when a node is clicked. The reason for this that the resulting page is book-markable by the browser. In other words the target URL ends up in the browser address text box.
The way I do this is in the backing bean as follows:
public void onNodeSelect(NodeSelectEvent event) {
selectedNode = event.getTreeNode();
String url = // compute some URL to move to based on selectedNode
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
try {
ec.redirect(url);
} catch (IOException ex) {
Logger.getLogger(Navigation.class.getName()).log(Level.SEVERE, null, ex);
}
}
To reiterate: Use a template even if that means a learning curve for you and it will actually force your webapp to be more cohesive and disciplined.
Eventually I solved the problem on my own.
It turned out to be some problem in the Javascript, that the tree node won't get highlighted when I specify <p:tree update="" />
to more than one destinations.
So after reading the code and YUI docs, finally I workaround the problem by adding a Javascript function to the onNodeClick handler of <p:tree />
, to force highlighting the selected node.
The function just forces highlighting the clicked node.
function highlightNode(e)
{
e.node.highlight();
}
At least works for my situation with using official Primefaces jars :)
精彩评论