Primefaces multiple dynamic content panels to be displayed - jsf

I'm trying to do a kind of simple customizable news view page into my web application, like Google's one but much simpler, with frames. Each frame object simply has his title and an url to be added as its content.
I'm using JSF and primefaces, both on their newest versions. So my backing bean, which is #ViewScoped, has access to the logged user, which is stored in a #SessionScoped bean, and that user has his corresponding frames loaded.
Problem comes when I try to iterate it over the #ViewScoped bean, because the only way I find to do it is with a c:forEach tag. That's the way I do:
<ui:composition 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:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<h:form>
<p:panel header="Noticias">
<h:panelGrid columns="#{fn:length(navegableHomeManager._UserFrames)}"
width="100%">
<c:forEach var="frame" items="#{navegableHomeManager._UserFrames}">
<p:column>
<p:panel header="#{frame._Name}" closable="true"
style="width:95%;height:500px;" id="#{frame._Name}">
<p:ajax event="close"
listener="#{navegableHomeManager.actionFrameClosed}" />
<ui:include src="#{frame._Path}" />
</p:panel>
</p:column>
</c:forEach>
</h:panelGrid>
</p:panel>
</h:form>
That iteration obviusly does not work with navegableHomeManager bean because it is #ViewScoped. So the bean will be rebuilt in each of the iterations. The solution I've reached uses another #SessionScoped bean between the navegableHomeManager and the loggedBean, so that way the frames are stored there and I can have access to them properly into the iteration. That's working with the code above.
However I don't think it should be compulsory to use a #SessionScoped bean (creating an specific bean for every single case) every time I want to iterate in that way. That's why I have tried using components to avoid the iteration.
<p:dataGrid columns="#{fn:length(navegableHomeManager._UserFrames)}"
value="#{navegableHomeManager._UserFrames}" var="frame">
<p:column>
<p:panel header="#{frame._Name}" closable="true"
style="width:95%;height:500px;">
<p:ajax event="close"
listener="#{navegableHomeManager.actionFrameClosed}" />
<ui:include src="#{frame._Path}" />
</p:panel>
</p:column>
</p:dataGrid>
It doesn't work neither when the bean is #ViewScoped or #SessionScoped, because even the frames properties are set, the ui:include tag has already been built with no destination path, so I can't render the destination path dinamically. I think that, as ui:include is being applied at the same time as c:forEach, using a c:forEach tag is really the only way to go through this.
Pool your ideas.
UPDATE
Here I post more xhtml code to help in the understanding of the context. The new's page is integrated into a template. That's the page which is targeted (/system/home/index.xhtml):
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
template="/templates/general_template.xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<ui:define name="metadata">
<f:event type="preRenderView"
listener="#{navegableHomeManager.initialize}" />
</ui:define>
<ui:define name="general_content">
<ui:include src="/system/home/home_view.xhtml" />
</ui:define>
And that's the way I also tried to do it, but not making the c:forEach tag to work:
<context-param>
<param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
<param-value>/system/home/index.xhtml</param-value>
</context-param>
And that's the backing bean header:
#ManagedBean
#ViewScoped
#URLMapping(id = "home", pattern = "/home", viewId = "/system/home/index.xhtml")
public class NavegableHomeManager extends SystemNavegable {
/**
*
*/
private static final long serialVersionUID = 6239319842919211716L;
#ManagedProperty(value = "#{loggedBean}")
private LoggedBean _LoggedBean;
//More stuff

Stick to <c:forEach>. It does the job you're looking for. The <ui:include> runs during view build time, so the iteration tag should also run during view build time.
As to the #ViewScoped bean problem, you've 2 options:
Turn off partial state saving for the particular view:
<context-param>
<param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
<param-value>/news.xhtml</param-value>
</context-param>
Change it to a #RequestScoped bean and use <f:param> and #ManagedProperty to maintain state across postbacks by request parameters.
There would be a third option if JSF 2.2 is available: just upgrade to JSF 2.2. They've fixed the chicken-egg problem in view scoped beans and partial state saving.

Related

JSF dynamically include src in "ui:include src="#{bean.pagePath}"

I tried to include multiple source page path using ui:include tag in different tabs. The problem is when i gave the source page path as static one means that page will be shown but if give the source page path from backing bean mean it won't include the page.
Here is my code
template.xhtml:
<p:layoutUnit position="center" id="layoutCenter">
<h:form id="tempFormId">
<p:tabView value="#{multiTabBean.tabsList}" var="useCase"
activeIndex="#{multiTabBean.activeTabIndex}">
<p:tab title="#{useCase.title}" closable="true">
<f:subview>
<h:panelGroup id="mainTempPanelGroupId" layout="block">
<ui:include src="#{useCase.path}" />
</h:panelGroup>
</f:subview>
</p:tab>
</p:tabView>
</h:form>
</p:layoutUnit>
bean:
public String menuAction() {
menuBtnRendered = true;
FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
selectedModuleViewId = externalContext.getRequestParameterMap().get(
"moduleViewId");
tabsList.add(new Tab(getTabId(selectedModuleViewId),
selectedModuleViewId, getModulePath(selectedModuleViewId)));
return null;
}
I'm using #ViewScoped.
<ui:include> runs during view build time (when XHTML is turned into JSF component tree). <p:tabView> runs during view render time (when JSF component tree needs to produce HTML).
So, <p:tabView var> isn't available when <ui:include> runs. This problem is detailed in this answer: JSTL in JSF2 Facelets... makes sense? (<ui:include> is a taghandler and has hence same lifecycle as JSTL tags).
You can solve this to a certain degree by using <c:forEach> to produce <p:tab>s instead of <p:tabView value>.
<p:tabView activeIndex="#{multiTabBean.activeTabIndex}">
<c:forEach items="#{multiTabBean.tabsList}" var="useCase" varStatus="loop">
<p:tab title="#{useCase.title}" closable="true">
<f:subview id="tab_#{loop.index}">
<h:panelGroup id="mainTempPanelGroupId" layout="block">
<ui:include src="#{useCase.path}" />
</h:panelGroup>
</f:subview>
</p:tab>
</c:forEach>
</p:tabView>
It's by the way interesting to see that you somehow used <f:subview> in your initial attempt which is completely useless over there (already taken into account by <p:tabView var>), but it's actually helpful in here (it creates a new NamingContainer around the tab content).
The above Community's answer hasn't worked for dynamic tabView
<p:tabView dynamic="true" ...
If i use dynamic="true" and c:foreach for tabs, when i add or remove a tab, do update #tabViewId, the tabview will reload "All content of existed tabs" => this is not the way to attribute "dynamic" work, it's not lazy.
My project has a problem with this, i had to customize the method encodeEnd of TabViewRenderer and do something else, but it's not simple.
I wondering whether there is a way to include XHTML templates at rendered time?

p:commandLink not fires action

p:commandLinks with ids cl1 and cl2 do not fire actions. There is nothing on Tomcat console, nothing on Firebug console.
Where should i look for the problem in such situations, i think i am totally desperate without any error or exception, in both consoles.
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:o="http://openfaces.org/"
xmlns:p="http://primefaces.org/ui">
<h:form>
<ui:repeat var="sharing" value="#{sharingController.myList}">
<ui:repeat var="sharingComment" value="#{sharing.subCommentList}">
<p:commandLink id="cl1" value="" process="#this" action="#{reportController.reportSharingComment(sharingComment)}" style="float:right;" id="sharingComment_alert" styleClass="icon_alert" title="#{msg['label.report']}" update=":messages" >
</p:commandLink>
<p:commandLink value="" id="cl2" process="#this" action="#{sharingController.deleteComment(sharingComment)}" style="float:right;" id="sharingComment_delete" styleClass="icon_delete" title="#{msg['label.delete']}" update="#form :messages">
</p:commandLink>
</ui:repeat>
</ui:repeat>
</h:form>
</ui:composition>
I tried with a concrete list in the nested ui:repeat in post construct then commandlinks was fired, but I must iterate over field lists like sub commentlists of every sharing in myList. I'm loading both myList and for every sharing I load the subCommentlist in a for in post construct, but I still cannot make the commandLinks fire.
h:commandLink / h:commandButton is not being invoked
The 4. point solved:
Putting the bean in the view scope and/or making sure that you load the data model in (post)constructor of the bean (and thus not in the getter method!) should fix it.

Getting page parameters for a requestscoped bean in a form

I have the following page:
<?xml version='1.0' encoding='UTF-8' ?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Fire - Registration</title>
</h:head>
<h:body>
<f:view>
<f:event type="preRenderView" listener="#{confirmPasswordResetBean.bindSessionKey()}"/>
</f:view>
<p:growl id="growl" showDetail="true" life="5000" />
<h:form>
<p:panel header="Select your new password">
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel for="newPassword" value="Type your new password"/>
<p:password id="newPassword"
value="#{confirmPasswordResetBean.firstPassword}"
feedback="true"/>
<p:outputLabel for="retypedPassword" value="Retype your password"/>
<p:password id="retypedPassword"
value="#{confirmPasswordResetBean.secondPassword}"/>
</h:panelGrid>
<p:commandButton id="confirmButton"
value="reset"
action="#{confirmPasswordResetBean.doResetPassword()}"
update=":growl"/>
</p:panel>
</h:form>
</h:body>
The backing bean used above is RequestScoped, and the page itself takes a single parameter (sessionKey)...what I want to do is to:
1. Bind sessionKey to a variable in the backing bean. This is straightforward enough.
2. Use the bound value of sessionKey when executing dedicated logic in the same bean, when the client presses the commandButton.
The problem is that pressing the button starts a new request, which invalidates both the current bean (with the bound value), as well as the external page context...I thus lose all means to get a hold of sessionKey from either the bean or the page parameters...how can I resolve this? I am relatively new to both web programming and JSF, so pardon me if this has an obvious answer.
Either put the bean in the view scope, so that it lives long as you're interacting with the same view, or pass the request parameter by <f:param> to the subsequent requests.
<p:commandButton ...>
<f:param name="sessionKey" value="#{param.sessionKey}" />
</p:commandButton>
By the way, you'd rather have used <f:viewParam> to bind the request parameter to the bean directly.
<f:metadata>
<f:viewParam name="sessionKey" value="#{bean.sessionKey}" />
</f:metadata>
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

JSF 2.0 ViewScoped life cycle

My problem is that one of my ViewScoped bean is created several time within the same view. The constructor of ViewScopedBean is created every time I select a node in the tree.
<h:form>
<p:tree value="#{treeBean.root}" var="node"
selectionMode="single" selection="#{viewScopedBean.selectedNode}">
<p:ajax event="select" update="selectedNode, treeBeanUpdate, otherBeanUpdate, panel" listener="#{treeBean.onNodeSelect}" />
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
Selected Node: <h:outputText value="#{viewScopedBean.selectedNode}" id="selectedNode"/><br/>
Current TreeBean: <h:outputText value="#{treeBean}" id="treeBeanUpdate"/><br/>
Current OtherBean: <h:outputText value="#{viewScopedBean}" id="otherBeanUpdate"/><br/>
<p:outputPanel id="panel">
<ag:profileComponent managedBean="#{viewScopedBean.profileBean}"/>
</p:outputPanel>
</h:form>
If I remove this part (reference to a composite component), the constructor of ViewScopedBean is not called:
<p:outputPanel id="panel">
<ag:profileComponent managedBean="#{viewScopedBean.profileBean}"/>
</p:outputPanel>
All the beans used are set as #ViewScoped.
#ManagedBean
#ViewScoped
public class ViewScopedBean implements Serializable {
private TreeNode selectedNode;
private ProfileBean profileBean;
public ViewScopedBean() {
System.out.println("Constructor of ViewScopedBean " + this);
}
#PostConstruct
public void init() {
System.out.println("ViewScoped init" + this);
profileBean = new ProfileBean();
}
}
Is it the correct behaviour? If not what can cause it?
Update: I tried to use an empty composite, and I have the same problem.
<?xml version="1.0" encoding="UTF-8"?>
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="managedBean" required="true"/>
</composite:interface>
<composite:implementation>
</composite:implementation>
</html>
But if I made the managedBean not required, that's fine.
Another thing I don't get is when the constructor is called, it seems that the object created is not used.
Initiating the view (console output):
Constructor of ViewScopedBean xxx.bean.ViewScopedBean#4e1d2b8e
2 clicks on the tree:
Constructor of ViewScopedBean xxx.bean.ViewScopedBean#4eb64f2e
Constructor of ViewScopedBean xxx.bean.ViewScopedBean#66863941
Then I open the debug window <ui:debug/>, the viewScopedBean is set to xxx.bean.ViewScopedBean#4e1d2b8e
The view scoped bean will be recreated on every request from/to the same view, when you use JSTL tags like <c:if>, <c:forEach> and so on in the view, or when you bind a JSF component as a property of the view scoped bean using binding attribute. That's apparently what's happening in your composite component.
You need to rewrite your composite component as such that it does not utilize any JSTL tags. Binding some JSF component as a property of the bean can also be avoided in many ways, but if that is really not avoidable, then disabling the partial state saving in web.xml should work in most of the cases:
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
If that doesn't work for you, then you really have to share your composite component implementation code with us so that we can point out the caveats and propose the right approaches.

facelets: passing bean name with ui:param to action attribute

Due to some custom components which expect a bean name (NOT the bean instance) in their attributes I need to pass the actual bean name between pages. As the bean itself is also used by non-custom components, I would like to avoid using additional ui:param (like described here Passing action in <rich:modalPanel>) since it will essentially specify the same bean.
Is it possible to specify component's action using bean name provided with ui:param?
Basically I am trying to achieve the following:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
template="/template.xhtml">
<ui:param name="beanName" value="sessionBean"/>
...
</ui:composition>
and template.xhtml is
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
template="/someothertemplate.xhtml">
</ui:define name="somename">
<h:form>
<a4j:commandButton value="test" action="#{beanName.delete}"/>
</h:form>
</ui:define>
</ui:composition>
Although delete method is properly defined (verified with action="#{sessionBean.delete}") the above code gives me
javax.faces.FacesException: #{beanName.delete}: javax.el.MethodNotFoundException: /template.xhtml #201,89 action="#{beanName.delete}": Method not found: sessionBean.delete()
You should be able to reference the bean via its scope:
<a4j:commandButton value="test"
action="#{sessionScope[beanName].delete}"/>
<a4j:commandButton value="test" action="#{bean[action]}" />
The params to pass
<ui:param name="bean" value="#{sessionBean}" />
<ui:param name="action" value="delete" />
you can use #{bean['delete']} if your action name is fixed.

Resources