ModalPanel using RichFaces - jsf-2

I'm trying to create a ModalPanel from a dataTable (RichFaces 4.5.1, MyFaces 2.2.6, Spring 3.1.1, Tomcat 7.0.27) but I can't.
The modalPanel has values ​​to be displayed based on the selected row in the table. When I click in a commandLink, trigger a actionListener should feed these values (localidadeMB.carregarColecoes()), but it does't work, because the reference to attributes of bean is null (has not been set by the f:setPropertyActionListener located in commandLink).
What was missing?
*page.xhtml
(...)
<f:view>
<h:form id="formConsulta">
<rich:dataTable id="tabela"
value="#{localidadeMB.getLocalidadesPorPalavra()}" var="loc"
rowKeyVar="row" rows="20" width="800px" render="scroller">
<rich:column>
(...)
</rich:column>
<rich:column>
<f:facet name="header">
<h:outputText value=""/>
</f:facet>
<a4j:commandLink id="editlink" ajaxSingle="true"
oncomplete="#rich:component('modalEditarLocalidade')}.show()"
actionListener="#{localidadeMB.carregarColecoes}"
render="modalEditarLocalidade">
<h:graphicImage value="/img/edit.png"/>
<f:setPropertyActionListener value="#{loc}" target="#{localidadeMB.localidade}" />
</a4j:commandLink>
</rich:column>
</rich:dataTable>
</h:form>
<ui:include src="modalPanel.xhtml" />
*modalPanel.xhtml
<ui:composition>
<rich:popupPanel id="modalEditarLocalidade" autosized="true"
modal="false" resizable="false">
<f:facet name="header">
<h:outputText value="Alterar localidade" />
</f:facet>
<f:facet name="controls">
<h:graphicImage id="modalClosePNG2" value="/img/close1.png"
style="cursor:default;"
onclick="Richfaces.hideModalPanel('modalEditarLocalidade')" />
</f:facet>
<h:form>
<h:outputLabel value="Nome da localidade:" for="nomeLocalidade" />
<h:inputText id="nomeLocalidade"
value="#{localidadeMB.localidade.nome}" required="true"
immediate="true"/>
</h:inputText>
</h:form>
</rich:popupPanel>
</ui:composition>
*ManagedBean
private Localidade localidade;
public void setLocalidade(Localidade l){
this.localidade = l;
}
public void carregarColecoes(ActionEvent action){
System.out.println(localidade.getNome());
***** print NULL *****
}

If you want to set up a variable first and then execute a method you have to use #action for that method, actionListeners are executed first but since both of your methods are actionListeners the localidadeMB.carregarColecoes is executed before the variable is set. (And btw. h:commandLink has no "ajaxSingle" or "oncomplete" attributes.)

With the suggestion of Makhiel and this link I decided.
The xhtml looked like this:
<a4j:commandLink id="editlink" ajaxSingle="true"
oncomplete="#{rich:component('modalEditarLocalidade')}.show()"
action="#{localidadeMB.carregarColecoes}"
render="modalEditarLocalidade">
<h:graphicImage value="/img/edit.png"/>
<f:setPropertyActionListener value="#{loc}"
target="#{localidadeMB.localidade}" />
</a4j:commandLink>
and ManagedBean like this:
public String carregarColecoes(){
(....)
}

Related

How to change the value of <p:dataTable> dynamically based on <p:selectItem>?

I am working with jsf 2.0 et Primefaces. i have a selectOneMenu that have dynamic values of datas that correspond to the user connected. I want that when i choose a data and click on the button view the list of emails related to the data selected will be shown on the dataTable.
<p:panel>
<p:selectOneMenu id="data" value="#{mailMB.database}" styleClass="auto" required="true" effect="fade" >
<f:selectItem itemLabel="Select Data" itemValue="" />
<f:selectItems value="#{dataMB.datas}" var="data" itemLabel="#{data.keyword}" itemValue="#{data.keyword}"/>
</p:selectOneMenu>
<p:commandButton value="View" action="#{mailMB.grabemails()}" ajax="true" update="datas" icon="ui-icon-circle-check" styleClass="ui-priority-primary" />
</p:panel>
<p:panel id="panelform" header="Emails List" >
<p:dataTable value="#{mailMB.emailsByData}" var="item" id="datas" rowsPerPageTemplate="5,10,15,20,25,30"
paginator="true" rows="10"
selectionMode="single" filteredValue="#{mailMB.filteredMails}" rowKey="#{item.id}"
selection="#{mailMB.selectedMail}">
<p:ajax event="rowSelect" update=":form:dataView , :form:confirmDelete, :form:viewButton" listener="#{dataMB.onRowSelect}"/>
<p:ajax event="rowToggle" />
<p:column style="width:2%" exportable="false">
<p:rowToggler />
</p:column>
<p:column sortBy="#{item.email}" filterBy="#{item.email}">
<f:facet name="header">
<h:outputText value="Email"/>
</f:facet>
<h:outputText value="#{item.email}"/>
</p:column>
</p:dataTable>
</p:panel>
and this is my method in the managed Bean that returns the list of emails by data using the named query:
public List<Email> getEmailsByData() {
System.out.println("the database" + getDatabase());
return emailsByData = mailBusinessLocal.mails(getDatabase());
}
public List<Email> grabemails() {
return emailsByData = mailBusinessLocal.mails(database);
}
when i choose a data and click view nothing happens and the databate return null as it shown on the glassfish log.
You need to put your <p:selectOneMenu> inside a <h:form>. That's my first guess.

form rendered on primefaces isn't calling the manage bean

I'm having problems with a form that is rendered by a booleanButtom on PrimeFaces 3.5
the form appear as expected but when I commit the values of the field come null.
The code of the pag:`
<p:panelGrid>
<p:row>
<p:column>
<h:form id="city">
<p:panelGrid columns="2">
<h:outputText value="Name: "/>
<p:inputText label="Name" value="#{managedBean.city.name}"/>
<h:outputText value="Status: "/>
<p:selectBooleanButton value="#{managedBean.city.status}" onLabel="Enable" offLabel="Disable">
<p:ajax listener="#{managedBean.changeStatusCity()}"/>
</p:selectBooleanButton>
<h:outputText value="Add neighborhood?"/>
<p:selectBooleanButton id="btAddNeighborhood" value="#{managedBean.addNeighborCity}" onLabel="Cancel" offLabel="Yes">
<p:ajax update=":addNeighbor" listener="#{managedBean.addNeighborCity()}"/>
</p:selectBooleanButton>
</p:panelGrid>
</h:form>
</p:column>
</p:row>
<p:row>
<p:column>
<h:form id="addNeighbor">
<p:panel header="Neighborhood" rendered="#{managedBean.addNeighborCity}">
<p:panelGrid columns="2">
<h:outputText value="Name: "/>
<p:inputText label="Name" value="#{managedBean.neighborhood.name}"/>
<h:outputText value="Status: "/>
<p:selectBooleanButton value="#{managedBean.neighborhood.status}" onLabel="Enable" offLabel="Disable" onIcon="ui-icon-check" offIcon="ui-icon-close">
<p:ajax listener="#{managedBean.changeStatusNeighbor()}"/>
</p:selectBooleanButton>
</p:panelGrid>
</p:panel>
</h:form>
<h:form id="formBt">
<p:commandButton id="bt" value="Add" actionListener="#{managedBean.saveNeighborCity()}" update=":addNeighbor, :city:btAddNeighborhood"/>
</h:form>
</p:column>
</p:row>
</p:panelGrid>`
And the manage bean
public void addNeighborCity(){
if(addNeighborCity){
neighborhood = new Neighborhood();
neighborhood .setStatus(true);
neighborhood .setStringStatus("Enable");
}else{
neighborhood = null;
}
}
public void changeStatusNeighbor() {
if (neighborhood .isStatus()) {
neighborhood .setStringStatus("Enable");
} else {
neighborhood .setStringStatus("Disable");
}
}
public void saveNeighborCity(){
city.getNeighborhoods().add(neighborhood );
neighborhood = null;
addNeighborCity = false;
}
All the input inside of the form that was rendered doesn't send the information to the manage bean and when I put the button that add the neighbor to the list of the city the button stop working and doesn't call the manage bean any more.
Does someone knows what I'm doing wrong or what is happening.
I'm using Primefaces3.5, GlassFish4.0 and JSF2.2
As you did not post the whole managed bean, I guess that you're using the default scope of the managed bean: #RequestScoped. In that case you should use #ViewScoped.
I solved the problem, I was using glassfish 4 and it forces the jsf2.2 even when you put the jsf2.1 in our project, then I changed to glassfish 3 and all work just fine, thanks for the answers, and I'm using #ScopeSession.

JSF 2 view scoped bean not updated when action is called second time

I have a view scoped arrayList as bean. This is used to display the editable columns of dataTable. When the page is displayed initially and I try to update the table contents the update works fine, however when I try to update any column the second time the values which are changed do not reflect in the arrayList bean (verified in the action method using break point). The action method is also a managed bean with view scope.
<managed-bean>
<managed-bean-name>financialListBean</managed-bean-name>
<managed-bean-class>java.util.ArrayList</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
Below is the code for dataTable
<h:form id="myform">
<h:dataTable id="financialListBean1"
value="#{financialListBean}" var="varfinancialListBean"
styleClass="dataTableEx" headerClass="headerClass"
footerClass="footerClass"
rowClasses="rowClass1, rowClass2"
columnClasses="columnClass1" border="0" cellpadding="2"
cellspacing="0">
<h:column id="columnEx17">
<h:selectBooleanCheckbox styleClass="inputRowSelect"
id="rowSelect3"
value="#{varfinancialListBean.rowSelected}"></h:selectBooleanCheckbox>
<f:facet name="header"></f:facet>
</h:column>
<h:column id="amount1column">
<f:facet name="header">
<h:outputText styleClass="outputText" value="Amount"
id="amount1text"></h:outputText>
</f:facet>
<h:inputText styleClass="small8Input" id="amount1"
value="#{varfinancialListBean.amount}" onkeypress="return only5DigitsEntry(this, event);" onkeyup="return checkRequiredFieldsForUpdateFinancialBtn(this.form, event);">
</h:inputText>
</h:column>
<h:column id="type1column">
<h:selectOneMenu styleClass="selectOneMenu" id="menu1" value="#{varfinancialListBean.type}">
<f:selectItem itemLabel="M" itemValue="M" />
<f:selectItem itemLabel="Y" itemValue="Y" />
<f:selectItem itemLabel="Z" itemValue="Z" />
<f:selectItem itemLabel="O" itemValue="O" />
<f:selectItem itemLabel="S" itemValue="S" />
</h:selectOneMenu>
<f:facet name="header">
<h:outputText styleClass="outputText" value="Type"
id="type1text"></h:outputText>
</f:facet>
</h:column>
<h:column id="recDate1column">
<f:facet name="header">
<h:outputText styleClass="outputText"
value="Recieve Date" id="recDate1text"></h:outputText>
</f:facet>
<h:inputText styleClass="outputText" id="recDate1"
value="#{varfinancialListBean.recDate}"
onclick="getClock($(this).attr('id'))" >
<f:convertDateTime pattern="MMM d, yyyy"/>
</h:inputText>
</h:column>
</h:dataTable>
<h:commandButton type="submit"
value="Update Financial Information"
styleClass="commandExButton" id="updateFinancialBtn"
action="#{pc_SocialServicesView.doFinancialUpdateBtnAction}">
<f:param name="mrn" value="#{pc_SocialServicesView.mrn}" />
</h:commandButton>
</h:form>
The action method:
public String doFinancialUpdateBtnAction() {
System.out.println("I am at doFinancialUpdateBtnAction");
try{
if(mrn.length()==0){
mrn=getFacesContext().getExternalContext().getRequestParameterMap().get("mrn");
}
setFinancialListBean(dba.updateFinancialAsistance
(getFinancialListBean(), mrn));
setErrorMsgBean("Updated successfully ...");
doInit(mrn);
}catch (Exception e) {
System.out.println("There is an exception at doFinancialUpdateBtnAction");
Log.out.error("Error in doFinancialUpdateBtnAction: "+e);
setErrorMsgBean("No record was updated ...");
e.printStackTrace();
}
return "";
}

GET Parameter View Scoped Bean

I have a strange effect on my JSF2/richfaces 4 project. I use a viewscoped bean and a datascroller to view some data from my backing bean. The bean is viewscoped and to pass the figureId parameter I fire the preRenderView event.
<f:metadata>
<f:viewParam name="figureId" value="#{pointEdit.figureId}" >
<f:convertNumber pattern="###" />
</f:viewParam>
<f:event type="preRenderView" listener="#{pointEdit.init}" />
</f:metadata>
Displays fine, but when I click on the second site of the datascroller I get a nullponter exception for this line: <f:event type="preRenderView" listener="#{pointEdit.init}" />.
javax.el.ELException: /pointEdit.xhtml #17,66 listener="#{pointEdit.init}": java.lang.NullPointerException
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:111)
at com.sun.faces.facelets.tag.jsf.core.DeclarativeSystemEventListener.processEvent(EventHandler.java:128)
at javax.faces.component.UIComponent$ComponentSystemEventListenerAdapter.processEvent(UIComponent.java:2477)
at javax.faces.event.SystemEvent.processListener(SystemEvent.java:106)
at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:2102)
at .....
Caused by: java.lang.NullPointerException
at com.ebcont.gtv.ePrometheus.web.backingbean.PointEdit.init(PointEdit.java:74) // <--first access to figure
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.el.parser.AstValue.invoke(AstValue.java:262)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
... 27 more
My Bean:
#ManagedBean
#ViewScoped
public class PointEdit implements Serializable {
public void init() {
FigureService figureService = Utils.getSpringBean(FigureService.class);
figure = figureService .getById(figureId); // figureId will NOT be passed from GET
pointListToDisplay = figure.getPoints(); // nullpointer :-(
Before I imported my new data it worked fine on my test figures.
Why is my figureId GET Parameter not found in the init function? With my testdata (5 figures) I never had a problem with this.
UPDATE:
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<body>
<h:messages errorStyle="color:red" warnStyle="color:yellow" />
<rich:tabPanel switchType="client">
<rich:tab header="Punkte">
<rich:panel>
<f:facet name="header">
#{msg.pointEditDetail_figure_header }
</f:facet>
<div style="position: relative;">
<h:graphicImage url="/image?figureid=#{pointEdit.figure.id}"
style="border: solid 2px #013476;z-index: -2;">
<a4j:repeat value="#{pointEdit.points}" var="thepoi">
<h:panelGroup layout="block"
style="margin-top: -27px;top:#{thepoi.y}px; left: #{thepoi.x}px; background-image: url('images/poipin.png');background-repeat:none;width: 25px; height:27px; position:absolute; z-index: -0.9;display:none;"
styleClass="poi #{thepoi.id }">
<div style="margin-top: 27px;">
<a4j:repeat value="#{thepoi.labels}" var="poilabel">
<h:panelGroup layout="block"
styleClass="poilabel label#{thepoi.id}" style="display:none;">
<div style="color: white; z-index: 1; position: relative;">
<h:outputText value="#{poilabel.locale.isoCode}:"
style="background-image: url('images/layerbackground.png'); background-repeat: both;" />
<h:outputText value="#{poilabel.label.labelText}"
style="background-image: url('images/layerbackground.png'); background-repeat: both;"
rendered="#{not empty poilabel.label.labelText}" />
<h:outputText value="Nicht verfügbar"
style="background-image: url('images/layerbackground.png'); background-repeat: both;"
rendered="#{empty poilabel.label.labelText }" />
</div>
</h:panelGroup>
</a4j:repeat>
</div>
</h:panelGroup>
</a4j:repeat>
</h:graphicImage>
</div>
<br/>
<h:commandButton value="#{msg.pointEditDetail_show_all_button}"
onclick="$('.poi').toggle()"
rendered="#{ not empty pointEdit.points}" />
<h:button outcome="viewer.xhtml" value="#{msg.pointEditDetail_button_viewer}">
<f:param name="figureId" value="#{pointEdit.figure.id}"/>
<f:param name="zoom" value="1"/>
</h:button>
</rich:panel>
<br />
<rich:panel>
<f:facet name="header">
#{msg.pointEditDetail_points_header }
</f:facet>
<h:form>
<rich:dataTable value="#{pointEdit.points}" var="point"
id="pointtable" rows="10" rowKeyVar="rowId">
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_table_header_rowkey}
</f:facet>
#{rowId+1}
</rich:column>
<rich:column sortBy="#{point.id}" id="id"
sortOrder="#{pointEdit.pointIdOrder}">
<f:facet name="header">
<a4j:commandLink
value="#{msg.pointEditDetail_table_header_point} #{msg.pointEditDetail_table_header_id }"
render="pointtable" action="#{pointEdit.sortByPointId}" />
</f:facet>
#{point.id}
</rich:column>
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_table_header_x}
</f:facet>
#{point.x }
</rich:column>
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_table_header_y}
</f:facet>
#{point.y }
</rich:column>
<!-- filter (Object that extends Filter<?>), filterMethod, filterExpression -->
<rich:column filter="#{pointEdit.labelFilter}">
<f:facet name="header">
#{msg.pointEditDetail_table_header_label}
<h:inputText value="#{pointEdit.labelFilterText}">
<a4j:ajax event="change" render="pointtable" execute="#this" requestDelay="700"
ignoreDupResponses="true"/>
</h:inputText>
</f:facet>
<a4j:repeat var="pointlabel" value="#{point.labels}">
#{pointlabel.locale.isoCode}:
<h:outputText value="#{pointlabel.label.labelText}"
rendered="#{not empty pointlabel.label}" />
<h:outputText value="#{msg.pointEditDetail_not_available}"
rendered="#{empty pointlabel.label}" />
<br />
</a4j:repeat>
</rich:column>
<rich:column style="text-align:center">
<f:facet name="header">
#{msg.pointEditDetail_table_header_show_point}
</f:facet>
<h:selectBooleanCheckbox styleClass="pinchk#{point.id}"
value="false"
onchange="checkboxdrivendisplay(this,'.#{point.id }');checkboxdrivendisplay(this,'.lblchk#{point.id }');"
onmouseover="jQuery('.#{point.id }').show(); jQuery('.lblchk#{point.id }').show();"
onmouseout="checkboxdrivendisplay(this,'.#{point.id }');checkboxdrivendisplay(this,'.lblchk#{point.id }');">
</h:selectBooleanCheckbox>
</rich:column>
<rich:column style="text-align:center;">
<f:facet name="header">
#{msg.pointEditDetail_table_header_show_label}
</f:facet>
<h:selectBooleanCheckbox style="display:none"
styleClass="lblchk#{point.id}" value="false"
onclick="checkboxdrivendisplay(this,'.label#{point.id }');"
onmouseover="jQuery('.label#{point.id}').show();"
onmouseout="checkboxdrivendisplay(this,'.label#{point.id }');">
</h:selectBooleanCheckbox>
</rich:column>
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_table_header_edit_label }
</f:facet>
<center>
<h:link outcome="labelEdit.xhtml" value="#{msg.pointEditDetail_table_edit_label}">
<f:param name="pointId" value="#{point.id}"/>
</h:link>
</center>
</rich:column>
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_table_header_tag }
</f:facet>
<a4j:repeat var="tag" value="#{point.tags}" varStatus="index">
<h:link outcome="search.xhtml" value="#{tag.tag}">
<f:param name="tags" value="true" />
<f:param name="labels" value="false" />
<f:param name="legends" value="false" />
<f:param name="query" value="#{tag.tag}" />
</h:link>
</a4j:repeat>
</rich:column>
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_table_header_edit_tag }
</f:facet>
<center>
<h:link outcome="tagEdit.xhtml" value="#{msg.pointEditDetail_table_edit_tag}">
<f:param name="pointId" value="#{point.id}"/>
</h:link>
</center>
</rich:column>
<f:facet name="footer">
<rich:dataScroller for="pointtable" />
</f:facet>
</rich:dataTable>
</h:form>
</rich:panel>
</rich:tab>
<rich:tab header="Daten">
<h:form>
<rich:panel id="legendpanel">
<f:facet name="header">
#{msg.pointEditDetail_legend_edit_header }
</f:facet>
<h:outputText rendered="#{not empty pointEdit.legendeStatus}"
value="#{msg.pointEditDetail_legend_edit_success}" />
<br />
<h:inputTextarea value="#{pointEdit.legende}" cols="40" rows="8"/> <br /> <br />
<a4j:commandButton value="#{msg.pointEditDetail_legend_edit_button} "
render="legendpanel legende" action="#{pointEdit.editLegend}" />
</rich:panel>
</h:form>
<br />
<h:form>
<rich:panel name="labelPanel">
<f:facet name="header">
#{msg.pointEditDetail_label_edit_header }
</f:facet>
<rich:dataTable value="#{pointEdit.labels}" var="label"
id="labelTable" rows="10">
<rich:column>
<f:facet name="header">
Id
</f:facet>
#{label.id }
</rich:column>
<rich:column>
<f:facet name="header">
#{msg.pointEditDetail_label_edit_table_header}
</f:facet>
<rich:inplaceInput value="#{label.labelText }" showControls="true" layout="block" style="width: 98%"
required="true">
<a4j:ajax event="change" render="pointtable" listener="#{pointEdit.editLabel(label.id) }" />
</rich:inplaceInput>
</rich:column>
<f:facet name="footer">
<rich:dataScroller for="labelTable" />
</f:facet>
</rich:dataTable>
</rich:panel>
</h:form>
<br />
</rich:tab>
<rich:tab header="Verknüpfen">
<ui:include src="linkFigures.xhtml" />
</rich:tab>
</rich:tabPanel>
<script type="text/javascript" src="javascript/eprometheus.js"></script>
</body>
</html>
You need to either pass that parameter as <f:param> in the command link so that it retains in the subsequent request:
<h:commandLink>
<f:param name="figureId" value="#{pointEdit.figureId}" />
</h:commandLink>
or to check in the init() if FacesContext#isPostback() equals to false before proceeding (so that it only runs on a fresh new GET request, not in the subsequent postbacks as the bean is view scoped and the properties are already been set anyway):
public void init() {
if (!FacesContext.getCurrentInstance().isPostback()) {
// ...
}
}
My new test images where 5 times larger then the images i got 4 testing. In my ViewScoped bean i had the figure as property so the whole byte[] had to be serialized.
After removing this design flaw it works again and also explains why the new images cause troubles!

Binding a managed bean instance to composite component

I have a composite component (collapsiblePanel). The component uses the "collapsible" bean to provide the toggle function. When I use the same component multiple times on a page, each instance of the component is bound to the same bean instance. How Can I achieve something like a component scoped bean?
collapsibleTemp.xhtml:
<cc:interface>
<cc:attribute name="model" required="true">
<cc:attribute name="collapsed" required="true" />
<cc:attribute name="toggle" required="true"
method-signature="java.lang.String f()" />
</cc:attribute>
<cc:actionSource name="toggle" />
<cc:facet name="header" />
<cc:facet name="body" />
</cc:interface>
<cc:implementation>
<h:panelGroup layout="block" styleClass="collapsiblePanel-header">
<h:commandButton id="toggle" action="#{cc.attrs.model.toggle}"
styleClass="collapsiblePanel-img"
image="#{cc.attrs.model.collapsed ? '/resources/images/plus.png' : '/resources/images/minus.png'}" />
<cc:renderFacet name="header" />
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{!cc.attrs.model.collapsed}">
<cc:insertChildren />
<cc:renderFacet name="body"></cc:renderFacet>
</h:panelGroup>
<h:outputStylesheet library="css" name="components.css" />
</cc:implementation>
The backing bean:
#ManagedBean
#ViewScoped
public class Collapsible {
private boolean collapsed = false;
public boolean isCollapsed() {
return collapsed;
}
public void setCollapsed(boolean collapsed) {
this.collapsed = collapsed;
}
public String toggle() {
collapsed = !collapsed;
return null;
}
}
Using Page
<h:form id="someid">
<jl:collapsibletemp id="collapsiblePanel1" model="#{collapsible}">
<f:facet name="header">
<h3>
<h:outputText value="Collapsible information" />
</h3>
</f:facet>
<f:facet name="body">
<h:outputText value="do something....." />
</f:facet>
<p />
</jl:collapsibletemp>
<jl:collapsibletemp id="collapsiblePanel2" model="#{collapsible}">
<f:facet name="header">
<h3>
<h:outputText value="Collapsible information" />
</h3>
</f:facet>
<f:facet name="body">
<h:outputText value="do some tabbing" />
</f:facet>
<p />
</jl:collapsibletemp>
<jl:collapsibletemp id="collapsiblePanel3" model="#{collapsible}">
<f:facet name="header">
<h3>
<h:outputText value="Collapsible information" />
</h3>
</f:facet>
<f:facet name="body">
<h:outputText value="notice board" />
</f:facet>
<p />
</jl:collapsibletemp>
</h:form>
You can use the componentType attribute of the <cc:interface> to define a "backing component".
E.g.
<cc:interface componentType="collapsiblePanel">
...
</cc:interface>
<cc:implementation>
...
<h:commandButton action="#{cc.toggle}" ... />
...
<h:panelGroup rendered="#{!cc.collapsed}" ...>
...
</cc:implementation>
with just a com.example.components.CollapsiblePanel
#FacesComponent(value="collapsiblePanel") // To be specified in componentType attribute.
public class CollapsiblePanel extends UINamingContainer { // Important! Must extend UINamingContainer.
private boolean collapsed;
public void toggle() {
collapsed = !collapsed;
}
public boolean isCollapsed() {
collapsed;
}
}
However, when you want to have multiple of those components, then you should declare physically separate instances of them in the view. If this needs to happen dynamically, then you need to use <c:forEach> to generate physically separate instances of them instead of <ui:repeat> with a single component. Otherwise you have to map all collapsed states by the client ID inside a Map<String, Boolean>. See for an example and more background information also Getting same instance of `componentType` in composite component on every use

Resources