In my code the CommandButton action does not work when I put it in the second or third PanelGroup. It only works when I put in the first PanelGroup. My code is shown below. What may be the problem?
<ui:define name="pageLocations">
<h:panelGroup layout="block" id="pageLocations">
<c:if test="#{param.typeTab == null && param.relationTab == null && param.propertyTab == null}">
<ui:param name="defaultHeaderTitle" value="Properties"/>
<!--<h:outputText value="Properties" />-->
</c:if>
<p class="breadcrumb">Admin <ezcomp:out value="raquo" />
Fields <ezcomp:out value="raquo" />
<strong>
#{param.pageHeaderTitle}#{defaultHeaderTitle}
</strong>
</p>
</h:panelGroup>
</ui:define>
<!--<ui:define></ui:define>-->
<ui:define name="pageHeaderTitle">
<h:outputText value="#{param.pageHeaderTitle}#{defaultHeaderTitle}" id="soso" />
</ui:define>
<ui:define name="sidemenu">
<ui:param name="fieldsPage" value="active"/>
</ui:define>
<ui:define name="admin-content">
<h:form prependId="false">
<h:panelGroup layout="block" class="well well-small" id="mainPanel">
<h:panelGroup layout="block" class="row-fluid">
<div class="span1"><ezcomp:out value="nbsp"/></div>
<div class="span4">
<ul class="nav nav-pills" style="margin-top:4px;margin-bottom:0">
<c:if test="#{param.typeTab == null && param.relationTab == null && param.propertyTab == null }">
<ui:param name="default" value="active"/>
<ui:param name="defaultHeaderTitle" value="Properties"/>
</c:if>
<li class="#{param.propertyTab} #{default}">
<p:commandLink value="Properties" immediate="true" update="mainPanel,fields,:soso,:pageLocations" >
<f:param name="propertyTab" value="active"/>
<f:param name="pageHeaderTitle" value="Properties"/>
</p:commandLink>
</li>
<li class="#{param.typeTab}">
<p:commandLink value="Types" immediate="true" async="true" update="mainPanel,fields,:soso,:pageLocations" >
<f:param name="typeTab" value="active"/>
<f:param name="pageHeaderTitle" value="Types"/>
</p:commandLink>
</li>
<li class="#{param.relationTab}">
<p:commandLink value="Fields Relations" immediate="true" update="mainPanel,fields,:soso,:pageLocations">
<f:param name="relationTab" value="active"/>
<f:param name="pageHeaderTitle" value="Fields Relations"/>
</p:commandLink>
</li>
</ul>
</div>
</h:panelGroup>
</h:panelGroup>
<h:panelGrid id="fields" width="100%">
<h:panelGroup layout="block" rendered="#{param.propertyTab == 'active' || default == 'active' }">
<ui:include src="property/properties.xhtml"></ui:include>
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{param.typeTab == 'active'}">
<ui:include src="type/types.xhtml"></ui:include>
</h:panelGroup>
<h:panelGroup layout="block" rendered="#{param.relationTab == 'active'}">
<ui:include src="fields-relations.xhtml"></ui:include>
<h:commandButton value="Create" actionListener="#{fieldsRelationsController.createRelations()}" >
<f:ajax listener="#{fieldsRelationsController.createRelations()}"/>
</h:commandButton>
</h:panelGroup>
</h:panelGrid>
</h:form>
</ui:define>
It's because those panel groups are conditionally rendered based on a request parameter which is not present anymore in the subsequent POST request initiated by the command button.
When JSF processes the POST request, the rendered condition is also re-evaluated. Due to lack of the request parameter, it evaluates false, so the command button component won't be processed, so the associated action won't be invoked.
To fix this, you need to pass the request parameter responsible for calculating the result of the rendered attribute in a <f:param> of the command button.
<h:commandButton value="Create" action="#{fieldsRelationsController.createRelations}">
<f:ajax />
<f:param name="relationTab" value="active"/>
</h:commandButton>
(note that I've replaced the actionListener by action and removed the double f:ajax listener as well, I don't know what you were thinking, but I'll assume it to be a leftover of unthoughtful shoots in the dark)
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5.
Related
I have some objects in a list witch are components and I implemented this to show them :
first.xhtml:
<h:form id="sceneForm">
<c:forEach items="#{templateController.model.selectedTemplate.templatesSet.toArray()}" var="templateControls" varStatus="ind">
<ui:include src="second.xhtml"/>
</c:forEach>
</h:form>
second.xhtml:
<c:forEach items="#{templateControls.controlAttributes.toArray()}" var="controlAttributes" >
<c:choose>
<c:when test="#{controlAttributes.controlAttributeType.name == 'top'}">
<ui:param name="top" value="#{controlAttributes.value}px" />
</c:when>
<c:when test="#{controlAttributes.controlAttributeType.name == 'left'}">
<ui:param name="left" value="#{controlAttributes.value}px" />
</c:when>
<c:when test="#{controlAttributes.controlAttributeType.name == 'width'}">
<ui:param name="width" value="#{controlAttributes.value}px" />
</c:when>
<c:when test="#{controlAttributes.controlAttributeType.name == 'height'}">
<ui:param name="height" value="#{controlAttributes.value}" />
</c:when>
</c:choose>
</c:forEach>
<c:if test="#{templateControls.controlType.type == 'Button'}">
<div style="top:#{top}; left:#{left}; width:#{width}; height:#{height}px;>
<div class="gui-component-inner">
<span>#{value}</span>
<em class="helper"></em>
</div>
</div>
</c:if>
I iterate throught my attributes list and I set some variables and after it I set my component with variables. This works fine but it is not optim. I make a button:
<p:commandButton value="Test" actionListener="#{templateController.testAction}" onstart="Utils.PrintTime()" oncomplete="Utils.PrintTime()"/>
Witch prints the time on request start and on request end, and it takes 2 second if, if I delete the whole <c:forEach> then it takes 0,05 seconds. How could I make a better request time with iteration? Any idea?
Why I get that minus I don`t know...
Also here is my solution:
I make an object with top,left,width,height and declared it in the TemplateControl object. On page load I iterate the templateControls.controlAttributes and I set top,left,width,height for each component. And in xhtml I simply write:
<c:if test="#{templateControls.controlType.type == 'Button'}">
<div style="top:#{templateControls.atr.top}; left:#{templateControls.atr.left}; width:#{templateControls.atr.width}; height:#{templateControls.atr.height}px;>
<div class="gui-component-inner">
<span>#{value}</span>
<em class="helper"></em>
</div>
</div>
</c:if>
Like this I make my iteration in java at the beginning and not in xhtml and I freed from the <c:forEach> and <c:if> tags and now my requests are very fast.
I'm rendering a tree of nodes recursively using the following two JSF composite components I created:
tree.xhtml:
...
<cc:implementation>
<h:panelGroup id="content" layout="block">
<ul>
<c:forEach items="#{cc.attrs.rootNode.children}" var="node">
<ui:include src="treeNode.xhtml">
<ui:param name="level" value="1" />
</ui:include>
</c:forEach>
</ul>
</h:panelGroup>
</cc:implementation>
treeNode.xhtml:
...
<cc:implementation>
<li>
#{node.label}
<h:selectBooleanCheckbox value="#{node.checked}" />
<c:if test="#{not empty node.children}">
<ul class="node-level-#{level}">
<c:forEach items="#{node.children}" var="node">
<ui:include src="treeNode.xhtml">
<ui:param name="level" value="#{level + 1}" />
</ui:include>
</c:forEach>
</ul>
</c:if>
</li>
</cc:implementation>
Every Node has the properties label, checked, and children (the latter being a list of Nodes).
I'm getting it all nicely rendered, but when I try to change values, by checking the checkboxes and submitting the form, it doesn't get stored. Next time I refresh the page I still get the initial state (all checkboxes unchecked).
What am I doing wrong?
I have a little problem with the rendered attribute. I want to use it for login, if someone connects for the first time on my website, he can log in, but when he's logged, he can't see the form. But when the page is loaded, I can't hide the form...
Maybe it would be easier with my code.
HTML
<h:panelGroup id="sidebar" layout="block">
<h:panelGroup id="sbox1" layout="block">
<h:panelGroup class="title" layout="block">
<h2> Espace Membre </h2>
</h:panelGroup>
<ul class="style2">
<h:form rendered="#{!membreCtrl.estConnecte}">
Connection : <h:outputText value="#{membreCtrl.estConnecte}"></h:outputText>
Login : <h:inputText id="login" value="#{membreCtrl.login}" /> <br/>
Password : <h:inputSecret id="mdp" value="#{membreCtrl.mdp}" /> <br/>
<h:commandButton action="#{membreCtrl.identifier()}" value="Se connecter" />
</h:form>
</ul>
</h:panelGroup>
Bean
public String identifier() {
membreConnecte = membreEJB.connecter(login, mdp);
if (membreConnecte == null) {
return "FAILURE";
}
estConnecte = true;
return "SUCCESS";
}
If I put the right login/password, I get on the index page, but then I would like to hide the <h:form ..that I wrote.
But it doesn't work. When I print the result in the Bean, my boolean "estConnecte" is true, but not when I write it on the HTML code.
Did you update the form after the button's click?
Put a p:outputPanel inside the form, if you are using Primefaces, and then update the form:
<h:form>
<p:outputPanel rendered="#{!membreCtrl.estConnecte}">
Connection : <h:outputText value="#{membreCtrl.estConnecte}"></h:outputText>
Login : <h:inputText id="login" value="#{membreCtrl.login}" /> <br/>
Password : <h:inputSecret id="mdp" value="#{membreCtrl.mdp}" /> <br/>
<p:commandButton action="#{membreCtrl.identifier()}" value="Se connecter" update="#form"/>
<p:outputPanel/>
</h:form>
I have the following Facelet page:
<ui:define name="content">
<h:form id="selectReport">
<div>
<h:selectOneMenu value="#{reportsController.selectedReport}">
<f:selectItems value="#{reportsController.reportsList}"/>
</h:selectOneMenu>
</div>
<div>
<h:commandButton value="Ir al reporte"
action="#{reportsController.goToReport}"/>
</div>
</h:form>
<h:form id="dateRangeSetupForm"
rendered="#{reportsController.showDateRangeSetupForm}">
<div>
<h:outputLabel value="Desde:"/>
<h:inputText id="fromDate"
value="#{reportsController.fromDate}"/>
</div>
<div>
<h:outputLabel value="Hasta:"/>
<h:inputText id="toDate"
value="#{reportsController.toDate}"/>
</div>
</h:form>
<h:form id="billOfLadingSetupForm"
rendered="#{reportsController.showBillOfLadingSetupForm}">
<div>
<h:outputLabel value="# Factura:"/>
<h:inputText id="invoiceNumber"
value="#{reportsController.invoiceNumber}"/>
</div>
</h:form>
<h:form id="submitForm">
<h:commandButton id="processReport" value="Generar Reporte"
action="#{reportsController.processReport}"/>
<h:commandButton id="goBack" value="Regresar"
action="mainMenu"/>
</h:form>
</ui:define>
In which I let the user select a report, and render a form to setup parameters depending on the report. The problem is that when I render for example the billOfLadingSetupForm and fill the inputText, then click on the processReport button the invoiceNumber property of my bean is not updated, it is set to null.
I have noticed that if I type Return after filling the inputText and then click the processReport button the property does get updated. This is strange I haven't face this problem before. Do you have any idea why this happens?
Whenever a form get submitted, then only the data inside that form will be sent. The data of the other forms won't be sent. That's by HTML specification. You need to put all inputs and buttons which belongs to each other inside the same <h:form>. Replace all your splitted dateRangeSetupForm, billOfLadingSetupForm and submitForm forms by <h:panelGroup> and put them all inside one and same <h:form>.
Something like this:
<ui:define name="content">
<h:form>
<div>
<h:selectOneMenu value="#{reportsController.selectedReport}">
<f:selectItems value="#{reportsController.reportsList}"/>
</h:selectOneMenu>
</div>
<div>
<h:commandButton value="Ir al reporte" action="#{reportsController.goToReport}"/>
</div>
</h:form>
<h:form>
<h:panelGroup id="dateRangeSetupForm" rendered="#{reportsController.showDateRangeSetupForm}">
<div>
<h:outputLabel value="Desde:"/>
<h:inputText id="fromDate" value="#{reportsController.fromDate}"/>
</div>
<div>
<h:outputLabel value="Hasta:"/>
<h:inputText id="toDate" value="#{reportsController.toDate}"/>
</div>
</h:panelGroup>
<h:panelGroup id="billOfLadingSetupForm" rendered="#{reportsController.showBillOfLadingSetupForm}">
<div>
<h:outputLabel value="# Factura:"/>
<h:inputText id="invoiceNumber" value="#{reportsController.invoiceNumber}"/>
</div>
</h:panelGroup>
<h:commandButton id="processReport" value="Generar Reporte" action="#{reportsController.processReport}"/>
<h:commandButton id="goBack" value="Regresar" action="mainMenu"/>
</h:form>
</ui:define>
Make sure that the bean is put in the view scope. Otherwise the conditions for the rendered attribute won't be preserved. See also commandButton/commandLink/ajax action/listener method not invoked or input value not updated
I have a page that load (in a panelGroup) two different page, due to the login status (logged, not logged). This is the main switch :
template.xhtml P.S. selector.page is "homepage" as default
<h:panelGroup layout="block" styleClass="contenitore">
<h:panelGroup layout="block">
<h:panelGroup layout="block" styleClass="menu_table" id="login">
<ui:insert name="login_homepage" />
</h:panelGroup>
<h:panelGroup layout="block" id="content">
<c:catch>
<ui:include src="/#{selector.page}/#{selector.page}.xhtml" />
</c:catch>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
homepage.xhtml
<h:panelGroup rendered="#{!user.loggedIn}">
<h:panelGroup layout="block" styleClass="content_title">
Homepage
</h:panelGroup>
</h:panelGroup>
<h:panelGroup rendered="#{user.loggedIn}">
<ui:include src="/profile/profile.xhtml" />
</h:panelGroup>
login
<ui:define name="login_homepage">
<h:form id="formLogin" prependId="false">
<h:inputHidden value="#{selector.page}" id="page" />
<h:panelGroup rendered="#{!user.loggedIn}">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:outputLabel styleClass="menu_span" value="Username" />
<h:inputText value="#{user.nickname}" id="nickname" />
<h:outputLabel styleClass="menu_span" value="Password" />
<h:inputSecret value="#{user.password}" id="password" />
<h:outputLabel styleClass="menu_span">
<h:commandButton value="Login" action="#{user.checkLogin}">
<f:ajax event="action" execute="nickname password page" render=":login :content err"/>
</h:commandButton>
</h:outputLabel>
</h:panelGroup>
<h:panelGroup rendered="#{user.loggedIn}">
<h:outputLabel styleClass="menu_title" value="LOGGED" />
</h:panelGroup>
</h:form>
</ui:define>
profile.xhtml
<h:panelGroup layout="block" id="profileContent">
<h:form id="formProfile">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup rendered="#{profileSelector.profilePage=='main'}">
<ui:include src="/profile/profile_main.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{profileSelector.profilePage=='edit' || profileSelector.profilePage=='editConfirm'}">
<ui:include src="/profile/profile_edit.xhtml" />
</h:panelGroup>
</h:form>
</h:panelGroup>
ProfileSelector is #ViewScope scoped. When i load the page and im logged, it initialize the ProfileSelector bean. Else, if i'm not logged and i do the login, it change the Content from homepage to profile, but the Bean is not initalized. So, how can i inizialize this bean when im not logged?
I think the code above is sufficent to understand the problem.
Cheers
A similar bug
http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-928
<c:catch>
<ui:include src="/#{selector.page}/#{selector.page}.xhtml" />
</c:catch>
The problem is that you are using JSTL elements which break #ViewScope use alternative.