How to initialize a certain MBean first when navigating to a page - jsf

I have a page split in 3. First part is a list of links which is bound to a mBean (MLeft), and the second is the current mBean (MCenter) of the page I'm in. MCenter inserts data into MLeft so that the links from the first part are custom to the page I'm currently in. The thing is that when the page is rendered and the links are evaluated MLeft is created before MCenter (because is found earlier in the page) and MCenter doesn't get the chance to insert the links in MLeft, so no links are displayed. I put a call to MCenter before the links using an output text referring a dummy property which is an empty string.
I don't like this workaround, I had this problem in the past too with Seam and #Out and I solved it like this. Is there a better approach?

Maybe you can use follow method:
<f:view beforePhase="#{userMB.verifyUser}" />
the method will be invoked when the page be loaded

I think you need to use templates:
template.xhtml
<ui:composition>
<h:head>
<title>
<ui:insert name="title" />
</title>
<h:outputStylesheet name="css/haleczander.css" />
</h:head>
<h:body>
<div class="left">
<ui:include src="static_links.xhtml />
<ui:repeat value="#{links}" var="link">
<h:outputLink value="#{link}">#{link}</h:outputLink>
</ui:repeat>
</div>
<div class="center">
<ui:insert name="content" />
</div>
</h:body>
</ui:composition>
content1.xhtml
<ui:composition template="template.xhtml">
<ui:define name="title">
Content page 1
</ui:define>
<ui:param name="links" value="#{middle.links}" />
<ui:define name="content">
Blah blah 1
</ui:define>
</ui:composition>
I'm assuming links is a list or an array of strings, but you could make anything of it: a list of custom MyLink object, ... (as long as there is an appropriate getter)
You could also replace middle.links with whatever you like, event a method call like #{middle.getLinks(page1)}

Just make Center a managed property of Left. E.g.
#ManagedBean
#RequestScoped
public class Left {
#ManagedProperty(value="#{center}")
private Center center;
#PostConstruct
public void init() {
// Initialize links based on Center here.
}
// ...
}

Related

p:remoteCommand does not invoke the declared action method

Web page :
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:body>
<ui:composition template="../../Template/template.xhtml">
<ui:define name="content">
<h:form>
<h:outputText id="montest" value="#{ProviderLogin.i}"/>
<button class="ZWButtonActionIntervention pfButtonWhite" type="button" onclick="testpageRC()"/>
<span>TESTING</span>
</button>
<p:remoteCommand name="testpageRC" process="#this" update="montest" action="#{ProviderLogin.TESTING()}"/>
<p:commandButton styleClass="ZWButtonActionIntervention pfButtonOrange" value="#{GestionIntervention.m_typeNonTraitee}" action="#{ProviderLogin.TESTING()}"/>
</h:form>
</ui:define>
</ui:composition>
</h:body>
My java class (Bean)
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
#SessionScoped
#ManagedBean(name="ProviderLogin")
public class ProviderLogin implements Serializable
{
private int i;
public int getI(){return i;}
public void TESTING(){i++;}
}
I have a breakpoint in the function 'TESTING()'
When I press the 'p:commandButton', the breakpoint is reached
When I press the 'button' (p:remoteCommand is called), the breakpoint is NOT reached
What is really strange, is that the 'p:remoteCommand' works for this: update="montest"
But, the method in the bean is not fired.
By the way, when I start to write #{... I have access to my bean (variable and methods)
I use Primefaces 6.2
Problem found.
Every web pages defines the content of a template.
In this template there is the section "content" that cointained 2 <h:form>.
One is renderer when the user is not logged.
The other one is rendered when the user is logged correctly.
In each page that re-define the content (when user is logged), i had a second section of <h:form>. It seems that action of the <p:remoteCommand> doesn't manage this well while <p:button> does. I just deleted that form on each pages and my problem was solved.
My template (content part)
<div id="content" style="padding: 10px">
<h:form rendered="#{!ProviderLogin.m_User.m_bLogged}">
<h:button value="Connexion" outcome="/Gestion/Connexion.xhtml"/>
</h:form>
<h:form id="formContent" rendered="#{ProviderLogin.m_User.m_bLogged}">
<ui:insert name="content" >
<ui:include src="content.xhtml" />
</ui:insert>
</h:form>
</div>
One page that re-define the content part (with 2nd form that gave me errors)
<h:body>
<ui:composition template="../Template/template.xhtml">
<ui:define name="content">
<h:form id="formInterventions">
PAGE CONTENT
</h:form>
</ui:define>
</ui:composition>
</h:body>
The same page that re-define the content part (without 2nd form)
then, my action of the <p:remoteCommand> works !
<h:body>
<ui:composition template="../Template/template.xhtml">
<ui:define name="content">
PAGE CONTENT
</ui:define>
</ui:composition>
</h:body>
I also give you this informations :
i use update of some controls like this showcase :
https://www.primefaces.org/showcase/ui/ajax/poll.xhtml
You need to give the id of the control you want to update
When you are using <h:form>, sometimes you need to also specify the id of the form like this :
update="formID:controlID"
Because of that <h:form> defined in my template (which i forgot), it wasn't working because i didn't expect that at all and i didn't give that form an ID, so basically, a default id (j_idt27) was given.
This means my update functionnality couldn't find the specified control id

How to display a wait indicator for f:viewAction?

I have a JSF page that loads the properties of an object (for which the id is passed in the URL). The loading can last more seconds, so I would like to display a wait/busy indicator or a "Loading..." message.
This is done using "viewAction"
<f:metadata>
<f:viewAction action="#{myBean.loadParams}" />
</f:metadata>
Is there a simple way to accomplish this goal? I'm using Primefaces.
PrimeFaces has already a component ready for that: the <p:outputPanel deferred="true">. You only need to make sure that the #{heavyBean} is only referenced in a component (and thus definitely not in a tagfile like <c:xxx> for the reasons explained here) within the <p:outputPanel> and not somewhere else.
...
#{notHeavyBean.property}
...
<p:outputPanel deferred="true">
...
#{heavyBean.property}
...
</p:outputPanel>
...
#{anotherNotHeavyBean.property}
...
Then you can do the heavy job in its #PostConstruct method. Do the job you originally did in <f:viewAction> there in the #PostConstruct.
#Named
#ViewScoped
public class HeavyBean implements Serializable {
#PostConstruct
public void init() {
// Heavy job here.
}
// ...
}
If you need to access properties of other beans, simply #Inject those beans in the HeavyBean. E.g. in case you needed the ID view param:
<f:viewParam name="id" value="#{notHeavyBean.id}" />
#Inject
private NotHeavyBean notHeavyBean; // Also #ViewScoped.
#PostConstruct
public void init() {
Long id = notHeavyBean.getId();
// Heavy job here.
}
The <p:outputPanel> already comes with an animated gif. You can easily customize it via CSS.
.ui-outputpanel-loading {
background-image: url("another.gif");
}
I would like to propose also this simple approach:
one "landing" page (the page where we first navigate in) with a wait indicator and an autoRun remoteCommand with an event that read the parameter "param" from the URL and save it in the bean.
the remoteCommand does a redirect to another page (where the long-running method loadParams is executed)
In this way the wait indicator is shown until the second page is ready to be displayed.
Do you see any weaknesses?
Here the landing page:
<!DOCTYPE html>
<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.org/ui">
<h:head>
...
</h:head>
<f:metadata>
<f:event type="postAddToView" listener="#{notHeavyBean.readProperty}" />
<f:viewParam name="param"/>
</f:metadata>
<h:body>
<p:outputPanel layout="block">
<i class="fa fa-circle-o-notch fa-spin layout-ajax-loader-icon" aria-hidden="true" style="font-size: 40px;position: relative;top: 50%;left: 50%;"></i>
</p:outputPanel>
<h:form>
<p:remoteCommand action="#{notHeavyBean.redirect}" autoRun="true"/>
</h:form>
</h:body>

dynamic view injection or routing

i have a JSF projekt and in there i have different views, which are backed by ManagedBeans.
What i would like to achieve is to change some views while others stay where they are. this has to happen dynamically. In other words. I want to inject and remove views from an xhtml page without a page refresh. I have no clue how to achieve this.
Even better would be a dynamic view injection based on urls. angularjs does that very well.
But even without routing it would be great.
Thanks in advance.
Here is an example in pseudo code:
<nav>
<h:link action="navigationBean.changeView(view1)" method="ajax">Link1</h:link>
<h:link action="navigationBean.changeView(view2)" method="ajax">Link2</h:link>
</nav>
<h:viewContainer>
// view selected by clicking the nav links should be injected here without page reload
</h:viewContainer>
What you ask is better done using Facelet templating. You'll be able that way to have a page template with the shared content (the navigation menu in your case) and make the rest of the views inherit from it.
What can I see from your suggested solution is that you're abusing the POST calls. #{fragmentsPresenter.changeView('viewOne')} doesn't make sense just because you already know where you want to go to when you press that link (to viewOne), So you'll be better using plain links for that.
Here you've got an example showing how to handle navigation in a proper way. Let's suppose you've got a view controller even you won't need it in most of the cases:
ViewController.java
/**
* Give the scope you want to your bean depending on what are your operations
* oriented to. This example could be #ApplicationScoped as well
*
* #author amaeztu
*
*/
#ManagedBean
#SessionScoped
public class ViewController {
/**
* Just gets the current view path and switches to the other one
*
* #return
*/
public String changeView() {
String viewId = FacesContext.getCurrentInstance().getViewRoot()
.getViewId();
if (viewId.equals("/view1.xhtml")) {
return "/view2";
} else {
return "/view1";
}
}
}
This controller's job is just to check what view are you coming from and switch to the other one. It's pointless to perform a POST request (to send a form) just to navigate to the other view, while you could evaluate it before page rendering.
Here you've got how the template view is built:
template.xhtml
<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">
<h:head />
<h:body>
<h:form>
<!-- Use POST requests like this only when you have
to determine the destination dinamically at server side -->
<h:commandButton value="Switch View with POST"
action="#{viewController.changeView}" />
<br />
</h:form>
<!-- For plain navigation, use GET requests -->
<h:link value="Go to view 1" outcome="/view1" />
<br />
<!-- Determine where we are at page rendering time
and evaluate the other view path -->
<h:link value="Switch view without POST"
outcome="#{view.viewId eq '/view1.xhtml' ? '/view2' : '/view1'}" />
<br />
<br />
<ui:insert name="content" />
</h:body>
</ui:composition>
This template page defines a shared button/link set and calls for content. I've implemented different kind of navigation options. Using <h:link /> is, in this case, the most straight-forward way. Check the second link, here we evaluate the current view id when it gets rendered and a link to go to the opposite one is created. Cool, isn't it?
Now here it is the implementation of the child views:
view1.xhtml
<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" template="/template.xhtml">
<ui:define name="content">
<!-- Here you could have some #ViewScoped
bean managing the content i.e. #{view1Bean} -->
View 1
</ui:define>
</ui:composition>
view2.xhtml
<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" template="/template.xhtml">
<ui:define name="content">
View 2
</ui:define>
</ui:composition>
You'll be able to type their address in your browser and see them, that's what's called bookmarkable ;-)
See also:
Get current page programmatically
Ok, i solved it as follows:
my View:
<h:body>
<nav>
<h:form>
<h:commandLink action="#{fragmentsPresenter.changeView('viewOne')}">
viewOne
<f:ajax execute="#this" render="fragment-container" />
</h:commandLink>
<h:commandLink action="#{fragmentsPresenter.changeView('viewTwo')}">
viewTwo
<f:ajax execute="#this" render="fragment-container" />
</h:commandLink>
</h:form>
</nav>
<h:panelGroup id="fragment-container">
<ui:fragment rendered="#{fragmentsPresenter.activeView('viewOne')}">
<div>i am view one!</div>
</ui:fragment>
<ui:fragment rendered="#{fragmentsPresenter.activeView('viewTwo')}">
<div>i am view Two!</div>
<ui:include src="fragment.xhtml"/>
</ui:fragment>
</h:panelGroup>
and my ManagedBean:
#ManagedBean
#SessionScoped
public class FragmentsPresenter {
private String activeView;
public void setActiveView(String viewName) { this.activeView = viewName; }
public String getActiveView() { return this.activeView; }
public FragmentsPresenter() { this.activeView = "viewOne"; }
public void changeView(String viewName) { this.activeView = viewName; }
public boolean activeView(String viewName) {
return activeView.equals(viewName);
}
}

Managed Been not updated with up to date information on second submit

I am having a problem here that seem to have the better of me.
Context
I have a p:dialog (primefaces) that show details of a JPA entity. From this dialog, the user can modify the information and submit it. Once submitted, the information is saved in DB (through JPA).
The p:dialog is "wrapped" in a Component for use in different situations.
Problem:
If I show the dialog with an entity selected from DB, modify some information and click on the save (submit) button: it works fine the first time. The DB is updated and p:dialog is hidden.
If I show again the dialog with the same entity, modify again a data from the p:dialog and submit again: everything seems to work fine (confirmation messages & logs) but the DB is not updated.
At all time, the information found in the p:dialog is right. The data found in the BackingBean & DB though, are up to date only after the first submit.
Another clue: if after a submit action I refresh the page, it will work for one more submit.
Debugging information:
According to the information Posted by the submit (long life to Firebug!!!) all the data posted are right (always up to date). But if I display in the log what the backing bean receives, it is the same content as the previous submit (and not the new information).
The data is posted correctly, but seems to be badly received/interpreted. It is just like if the problem was occurring at the reception of the submit's post, in one of the RestoreView, ApplyRequestValue, ProcessValidation or UpdateModelValue phases of the JSF life cycle.
So, the reason why the second save (submit) seems to work but doesn't is because the data saved in the DB is the same for every subsequent submit..... Why?
I use Glassfish 3.1.2, Mojarra 2.1.13, JSF, PrimeFaces, CDI, JPA, Hibernate...
Code Snipets:
page including the p:dialog (cmpnt:dataEntryDialog) as Component:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:cmpnt="http://java.sun.com/jsf/composite/component"
>
<h:head>
<title>
Test!!!
</title>
</h:head>
<h:body>
<h:commandButton type="button" onclick="PVDlg.show();" value="show dlg"/>
<cmpnt:dataEntryDialog id="PVDataEntry" video="#{processStatus.testedVideo}" fieldGroupId="2"
header="This is a test"
widgetVar="PVDlg" render="#this"/>
</h:body>
</html>
p:dialog's component implementation (cmpnt:dataEntryDialog):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:c="http://java.sun.com/jsp/jstl/core"
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:p="http://primefaces.org/ui">
<composite:interface componentType="dataEntryComponent">
<composite:attribute name="video" required="true"/>
<composite:attribute name="widgetVar" required="true"/>
<composite:attribute name="render" required="false"/>
<composite:attribute name="closeActionListener" method-signature="void listener(org.primefaces.event.CloseEvent)" required="false" />
[... other attributes]
</composite:interface>
<composite:implementation>
<h:outputStylesheet library="css" name="dataEntryDialog.css" target="head" />
<div id="#{cc.clientId}">
<script type="text/javascript">
function handleDataEntrySaveAttempt(xhr, status, args) {
if( args.validationFailed || !args.saved ) {
jQuery('#' + #{cc.clientId} + ':cmpntDataEntryDialog').effect("shake", {times:3}, 100);
} else {
${cc.attrs.widgetVar}.hide();
}
return true;
}
</script>
<p:dialog
id="cmpntDataEntryDialog"
header="#{cc.attrs.header}"
widgetVar="#{cc.attrs.widgetVar}"
resizable="false"
showEffect="fade"
hideEffect="fade"
dynamic="true"
minimizable="true"
maximizable="false"
width="550"
height="500"
>
<h:form id="cmpntDataEntryForm" style="position:relative;">
<div style="height:460px;">
<div style="width:100%;height:100%;margin-bottom:5px;overflow:auto;">
<ui:repeat value="#{dataEntryDialog.loadDataEntryFields( cc.attrs.video, cc.attrs.fieldGroupId )}" var="field" varStatus="fieldRankInfo">
<div style="position:relative;width:100%;height:24px;margin:4px 0px;">
<h:outputText value="#{field.fieldName}:" style="vertical-align:middle;" styleClass="margin"/>
<p:calendar id="cmpntInputDate" value="#{field.value}" rendered="#{'java.util.Date' eq field.type}" styleClass="input margin" effect="drop" />
<p:selectOneMenu id="cmpntInputComboBox" value="#{field.value}" rendered="#{'ComboBox' eq field.type}" styleClass="input margin">
<f:selectItem itemLabel="SelectAValue"/>
<f:selectItems value="#{field.possibleValues}"/>
<f:converter converterId="com.ctec.world.ConvertInteger" />
</p:selectOneMenu>
[... some other optionally rendered fields for different data types]
</div>
</ui:repeat>
</div>
</div>
<div style="position:relative;bottom:0;">
<div style="float:right;margin-top:5px;">
<p:commandButton id="cmpntSubmit" action="#{dataEntryDialog.save( cc.attrs.video.video )}"
value="${cc.resourceBundleMap.dataEntryDialog_Save}"
process="#form" update="${cc.attrs.render} #form"
styleClass="margin" oncomplete="handleDataEntrySaveAttempt( xhr, status, args )"/>
<p:commandButton id="cmpntCancel"
value="${cc.resourceBundleMap.dataEntryDialog_Cancel}"
onclick="${cc.attrs.widgetVar}.hide();" styleClass="margin"/>
</div>
</div>
</h:form>
</p:dialog>
</div>
</composite:implementation>
</html>
Concerning the Managed beans, they are plain CDI #Named #SessionScoped bean.
ADDITIONAL INFORMATION:
I made further tests: went through phase listener to see if there is any object accessible from there having interesting information... no luck here until now.
I've got it! The problem is not on the presentation layer (what a surprise!). It is related on my logic. A little while ago, I have fixed an JPA Optimistic Lock Exception by changing entity instances (no longer managed by the entityManager) with the managed instance returned by the entity manager's merge method. My design wasn't supporting that change everywhere as expected... and I got lured by the post content which was right but not going in the entity instance I was expecting it to be. I guess more experience in web development won't hurt!

modalPanel lazy rendering when displayed

Motivation: I want to reduce the size of the page when is accessed, so I thought that lazy rendering on modalPanels would help. The idea is to render the modalPanel when the user clicks the link that displays it.
I want to lazy render on rich:modalPanel when the link to display it is clicked. To achieve this I've found a way:
Code of the modalPanel, wrapped inside a a4j:outputPanel
<a4j:outputPanel id="a4jPanel">
<rich:modalPanel id="panel" rendered="#{bean.renderPanel}">
<!-- here modalPanel things -->
</rich:modalPanel>
</a4j:outputPanel>
Code of the backing bean (session scope):
public boolean isRenderPanel() {
return renderPanel; //default value is false;
}
public void setRenderPanel(boolean value){
this.renderPanel=value;
}
public setRenderFalse(){
this.setRenderPanel(false);
}
Code of the page where it is invoked:
<a4j:form>
<a4j:jsFunction name="setRenderFalse" action="#{user.setRenderFalse}"/>
<a4j:commandLink value="render and show" oncomplete="Richfaces.showModalPanel('panel');setRenderFalse();" reRender="a4jPanel">
<f:setPropertyActionListener target="#{user.renderPanel}" value="true" />
</a4j:commandLink>
</a4j:form>
Problems:
The modalPanel needs to be wrapped inside an a4j:outputPanel because reRendering directly the modalPanel does not work (I never understood why).
After rendering it, an extra request is needed to set the render value to false (the bean is session scoped). Otherwise if we reload the page there would not be any lazy rendering because the value was set to true.
The backing bean has to handle one property to keep the state for each modalPanel, although this property is set to true whenever the link is clicked and set to false when the request is finished. I've tried to keep the rendered state with JS variables but it does not seem to work (they are just read once the page is loaded and never again).
Any more elegant way to do this?
There is a nice solution regarding your question. All is needed is a way to detect postback and couple of xhtmls.
First of all we need a bean that will help with indication of postback
public class HelperBean {
public boolean isPostback() {
FacesContext context = FacesContext.getCurrentInstance();
return context.getRenderKit().getResponseStateManager().isPostback(context);
}
}
empty.xhtml - for a blank content
<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/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
</ui:composition>
modal.xhtml - for wrapping the modal definition
<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/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<rich:modalPanel id="myLazyModal">
<h:outputText value="Modal Content"/>
</rich:modalPanel>
</ui:composition>
lazyModal.xhtml - for handling inclusion of the above xhtmls
<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/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich">
<a4j:include id="lazyModal" layout="block"
viewId="#{helperBean.postback ? 'modal.xhtml' : 'empty.xhtml'}"/>
</ui:composition>
finally use it
<h:form id="frmTest">
<a4j:include id="lazyModalContainer" layout="block" viewId="lazyModal.xhtml"/>
<a4j:commandButton id="btnSubmit" value="Submit" reRender="lazyModalContainer"
oncomplete="Richfaces.showModalPanel('myLazyModal');"/>
</h:form>
Now when the page is loaded empty.xhtml will be included till btnSubmit is clicked.
Regarding to the problems you mentioned (1):
Re-rendering components with the rendered attribute is a bit catchy. When the rendered expression is evaluated to false no markup is sent back to the client. Therefore, supplying the id of the none rendered component to the reRender attribute will never work cause there is no such id on the client side (DOM).
i think you should make separate xhtml(facelet) of modal panel and use ui:include and than on link click the link no need of boolean property than.
enter code here : <ui:include src="modalPanel path">, <a4j:commandLink id="abclink" oncomplete="#{rich:component('yourPanelname')}.show()" reRender="yourPanelForm"/>
Another solution is to set the render attribute of your modalpanel programmatically in the JSF component tree. So you wont't need an additional backing bean which has to handle one property to keep the state for each modalPanel:
Managed Bean:
public void togglePanel(ActionEvent event) {
UIComponent component = event.getComponent();
String forId = (String) component.getAttributes().get("for");
FacesContext currentInstance = FacesContext.getCurrentInstance();
UIComponent findComponent = ComponentFinder.findComponent(currentInstance.getViewRoot(), forId);
findComponent.setRendered(!findComponent.isRendered());
}
View:
Open the panel:
<a4j:commandLink actionListener="#{myBean.togglePanel}" value="Open">
<f:attribute name="for" value="targetPanelId" />
Close the Panel:
<a4j:commandLink id="closePanel" actionListener="#{myBean.togglePanel}" value="someLabel">
<f:attribute name="for" value="targetPanelId" />
The modalpanel:
<a4j:outputPanel ajaxRendered="true">
<rich:modalPanel id="targetPanelId" width="800" height="500" rendered="false" showWhenRendered="true">

Resources