I'm using the new version of OmniFaces 1.8.1, and particullary I start to use the new tag: <o:massAttribute>. Basically, I have the following form with conditionally rendered and disabled fields:
<h:form id="formABMProducto">
<h:panelGrid id="datosProducto" columns="4">
<o:massAttribute name="rendered" value="#{cc.attrs.page != 'baja'}">
<h:outputLabel for="codigo" ... />
<h:inputText id="codigo" ... />
<rich:message for="codigo" />
<h:panelGroup />
</o:massAttribute>
<o:massAttribute name="rendered" value="#{cc.attrs.page eq 'baja'}">
<h:outputLabel for="codigo" .../>
<rich:autocomplete id="codigoProducto" ... />
<rich:message for="codigo" />
<h:panelGroup />
</o:massAttribute>
<o:massAttribute name="disabled" value="#{cc.attrs.disableComponents}">
<h:outputLabel for="nombre" ... />
<h:inputTextarea id="nombre" ... />
<rich:message for="nombre" />
<span />
<h:outputLabel for="descripcion" ... />
<h:inputTextarea id="descripcion" ... />
<rich:message for="descripcion" />
<span />
</o:massAttribute>
<h:outputLabel value="#{msgs['producto.abm.panel.proveedor.tipo']}" for="CmbTipoProveedor"/>
<rich:select id="CmbTipoProveedor" ... />
<rich:message for="CmbTipoProveedor" />
<a4j:commandButton ... />
</h:panelGrid>
</h:form>
However, when I open the page, the third <o:massAttribute> is also disabling another input fields codigo and codigoProducto. I think this isn't the expected behaviour.
Indeed, this was a bug. The <o:massAttribute> got applied on all children of the parent UIComponent instead of only those contained in the tag. It would theoretically have worked when you've wrapped each <o:massAttribute> in its own UIComponent like <h:panelGroup> or so. However, this is clearly not an option in case of a <h:panelGrid> wherein you'd like to put the children each in its own column.
I reproduced your problem, filled issue 51 about this bug and fixed it in the current 2.0 snapshot. Please give it a try and sorry for any inconvenience.
Related
I want one requiredmessage for two h:selectOneMenu components, that is when a user submits the form if one of those selects values is not null, the bean method should be called, otherwise(both of them null) : I should tell him to select at least one, is it possible? or do I have to use JS.
Thanks in advance,
I'd use the OmniFaces validateOne validator for this or the validateOneOrMore if filling both is allowed too.
Code example from their site:
<h:form>
<h3>Please fill out only one of two fields</h3>
<o:validateOne id="one" components="foo bar" />
<h:panelGrid columns="3">
<o:outputLabel for="foo" value="Foo" />
<h:inputText id="foo" />
<h:message for="foo" />
<o:outputLabel for="bar" value="Bar" />
<h:inputText id="bar" />
<h:message for="bar" />
<h:panelGroup />
<h:commandButton value="submit">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:panelGroup>
<h:message for="one" />
<h:outputText value="OK!" rendered="#{facesContext.postback and not facesContext.validationFailed}" />
</h:panelGroup>
</h:panelGrid>
</h:form>
My problem is a little bit complex, but I'll give an example.
I already have a user.xhtml page (and a MB that uses it) where I register an user
<p:outputLabel value="Name:" /> <h:outputText value="#{userMB.bean.name}" />
<p:outputLabel value="e-mail:" /> <h:outputText value="#{userMB.bean.email}" />
etc...
Now I create an UserAdmMB that inherits UserMB, with another fields. I want to reuse the XHTML that exists, like using <ui:include>:
<ui:include src="user.xhtml" />
<p:outputLabel value="Address:" />
<h:outputText value="#{userAdmMB.anotherbean.address}" />
But the first XHTML already has userMB in it (to be used in another access point). How is the better way to do that?
Refactor the bean as <ui:param> of <ui:include>.
The new include:
<p:outputLabel value="Name:" /> <h:outputText value="#{user.name}" />
<p:outputLabel value="Email:" /> <h:outputText value="#{user.email}" />
...
The clients:
<ui:include src="user.xhtml">
<ui:param name="user" value="#{someBean.user}" />
</ui:include>
<ui:include src="user.xhtml">
<ui:param name="user" value="#{someAdminBean.user}" />
</ui:include>
In this page this part get called twice. I can't see the reason for this. The problem this leads to is that the selections in the selectonemenu will get reset and then return the incorrect result for the second call.
ServiceSeries is a session bean.
Can anyone tell me why this double call happens?
<c:forEach var="list" items="#{serviceSeries.getSeriesForPlayerInfo(club.name, player.stringID, st, calendarBean)}">
<!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://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:p="http://primefaces.org/ui">
<ui:composition template="/WEB-INF/templates/template.xhtml">
<ui:define name="content">
<h:form>
<div id="left">
<h:commandLink action="player" value="Gå till spelare" />
<br />
<h:commandLink action="club" value="Gå till Klubb" />
<br />
<h:commandLink action="serieType" value="Gå till Serie typ" />
<br />
<h:commandLink action="serie" value="Gå till En serie" />
<br />
<h:commandLink action="serieTotal" value="Gå till Serie Total" />
<br />
<h:commandLink action="showAverages" value="Gå till snittlista" />
<br />
</div>
<div id="right">
<div id="pageHeader">Snitt information</div>
<h:panelGrid columns="2">
Spelare
<p:selectOneMenu value="#{player}"
converter="playerConverter" id="playerList">
<f:selectItem itemLabel="---" noSelectionOption="true" />
<f:selectItems value="#{servicePlayer.allPlayers}"
var="n"
itemValue="#{n}"
itemLabel="#{n.combinedName}"
itemLabelEscaped="true"/>
</p:selectOneMenu>
<h:outputText value="Klubb"></h:outputText>
<p:selectOneMenu id="ClubMenu" value="#{club.name}">
<f:selectItems value="#{serviceHCP.clubs}" />
</p:selectOneMenu>
<h:outputText value="Serietyp"></h:outputText>
<p:selectOneMenu value="#{st}"
converter="serieTypeConverter" id="serieTypeList">
<f:selectItem itemLabel="---" noSelectionOption="true" />
<f:selectItems value="#{serviceSerieType.serieTypes}"
var="st"
itemValue="#{st}"
itemLabel="#{st.serie_type}"
itemLabelEscaped="true"/>
</p:selectOneMenu>
<h:outputText value="Startdatum"></h:outputText>
<p:calendar value="#{calendarBean.date1}" id="popupButtonCal" showOn="button" pattern="yyyy-MM-dd HH:mm:ss" >
</p:calendar>
<h:outputText value="Slutdatum"></h:outputText>
<p:calendar value="#{calendarBean.date2}" id="popupButtonCal2" showOn="button" pattern="yyyy-MM-dd HH:mm:ss" >
</p:calendar>
<h:outputText value=""></h:outputText>
<h:commandButton value="Visa lista" action="showSeriesInfo">
</h:commandButton>
</h:panelGrid>
</div>
<div id="right">
Players
<br />
<!-- h:form -->
<h:panelGrid columns="9" border="1" cellpadding="3">
<h:outputText value="Namn" />
<h:outputText value="ID" />
<h:outputText value="Klubb" />
<h:outputText value="Datum" />
<h:outputText value="typ" />
<h:outputText value="Info" />
<h:outputText value="Antal serier" />
<h:outputText value="Total" />
<h:outputText value="Snitt" />
<c:forEach var="list" items="#{serviceSeries.getSeriesForPlayerInfo(club.name, player.stringID, st, calendarBean)}">
<h:outputText value=" #{list[0].toString() }" />
<h:outputText value=" #{list[1].toString() }" />
<h:outputText value="#{serie.getSerieDateString(list[2]) }" />
<h:outputText value="#{list[3].toString()}"/>
<h:outputText value=" #{list[4].toString() }" />
<h:outputText value=" #{list[5].toString() }" />
<h:outputText value=" #{list[6].toString() }" />
<h:outputText value=" #{list[7].toString() }" />
<h:outputText value=" #{list[8].toString() }" />
</c:forEach>
</h:panelGrid>
</div>
</h:form>
</ui:define>
</ui:composition>
</html>
If I understand your problem description correctly, its expected behavior; JSF has 6 lifecycles for a request and the same method may be invoked in each and every one of them; in my experience it sometimes happens twice and sometimes happens three times in a single request depending on which phases JSF invokes and which ones it skips.
Its your job to know that this can happen, when it can happen (by studying the lifecycle phases) and design your code accordingly, for example by ensuring that the methods return exactly the same thing for each and every lifecycle phase. There are multiple strategies that may apply, such as utilizing specific scopes (view, session, conversation), through lazy initialization or by using a bean init method annotated with PostConstruct to do one time initialization for a bean.
If you need further assistance, I suggest you post the relevant server side (Java) code too. the problem originates there somewhere.
This might help: http://balusc.blogspot.nl/2006/09/debug-jsf-lifecycle.html
I have bean struggling to understand how to use the rich:popupPanel component in the right way. There are (at least not that I could find) few post about how to use the rich:popupPanel and how to submit values from it.
To make matter worse the panel seams to add (when checking the html) a hard coded "_content" to its component id name (to the div generated). I have tried to use aj4:region tag to partial render the complete form. But that didn't seamed to work, cause nothing where posted to managed bean. So now I have one option left, where the panel has its own form, outside the main one on the page.
I can see that the evaluation of the form (popup) values is happening, but not the execution of the bean function that persist the values (I see the POST request of the command button). The only reason I can think of at the moment, is that the pop-up panel use another bean to persist the values that the main form on the page (both of them are session scoped).
I am thinking of omit the pop-up panel all together, since it seams so hard to make this work. Maybe its a well know secret, since it so few post about it. It behaves the same if if use componentController or only a a4j:commanLink.
How is it possible to submit values from a rich:popupPanel and invoke a backing bean function to persist the pop-up form values ?
Appreciate if someone can shed some light on this, greetings Chris.
I use Richfaces 4.0-final on Glassfish 3.1
<h:form id="main_form">
<!-- Command for popup -->
<a4j:commandLink actionListener="#{userController.prepareCreateSysRequest}" oncomplete="#{rich:component('popup_sys_user_req_form:popup_sys_user_req')}.show(); return false;"
execute="#this" value="Request New Sector/Category" />
...
<a4j:commandButton action="#{projectController.Create}" ...>
</h:form>
<h:form id="popup_sys_user_req_form">
<rich:popupPanel id="popup_sys_user_req" modal="true" autosized="true" resizeable="false">
<f:facet name="header">
<h:outputText value="New Project Request" />
</f:facet>
<f:facet name="controls">
<h:outputLink value="#"
onclick="#{rich:component('popup_sys_user_req')}.hide(); return false;">
X
</h:outputLink>
</f:facet>
<h:panelGrid columns="2">
<h:outputLabel value="Request New:" />
<h:selectOneMenu id="sys_req_type" value="#{userController.selectedSysRequestType}" required="true" requiredMessage="Request Type is required" title="Request Type">
<f:selectItems value="#{userController.getSysRequestTypeItems()}">
</f:selectItems>
</h:selectOneMenu>
<h:outputLabel value="Description:" />
<h:inputTextarea id="user_req_desc" value="#{userController.selectedSysUserRequest.description}" required="true" requiredMessage="Decription is missing" />
</h:panelGrid>
<a4j:commandButton action="#{userController.CreateSysUserRequest}" onclick="#{rich:component('popup_sys_user_req')}.hide(); return false;" execute="#form" render="popup_sys_user_req_form" value="Send Request" />
</rich:popupPanel>
</h:form>
For what I have done I used to have the issue to got to submit twice only the first time.
To fix it the form got to be outside the popupPane. And also that the popupPanel should have the attibute domElementAttachment="form".
Example.
<h:form>
<rich:popupPanel id="shipmentItemUpdateDialog"
autosized="true"
domElementAttachment="form">
<f:facet name="header">
<h:panelGroup>
<h:outputText value="#{shipmentBundle.shipmentItemDetailsHeader}" />
</h:panelGroup>
</f:facet>
<f:facet name="controls">
<h:commandLink>
<h:graphicImage value="/core/images/modal/close.png"/>
<rich:componentControl target="shipmentItemUpdateDialog" operation="hide" />
</h:commandLink>
</f:facet>
<h:outputText for="shipmentItemName"
value="#{coreBundle.requiredChar} #{shipmentBundle.shipmentItemName}"
/>
<h:inputText id="shipmentItemName"
disabled ="false"
required ="true"
value="#{shipmentItemController.shipmentItemUI.value.name}"
label="#{shipmentBundle.shipmentItemName}"
size="40" >
</h:inputText>
<h:outputText for="shipmentItemCode"
value="#{coreBundle.requiredChar} #{shipmentBundle.shipmentItemCode}"
/>
<h:inputText id="shipmentItemCode"
disabled ="false"
required ="true"
value="#{shipmentItemController.shipmentItemUI.value.code}"
label="#{shipmentBundle.shipmentItemCode}"
size="40" >
</h:inputText>
<h:outputText value="#{coreBundle.requiredChar} #{shipmentBundle.shipmentItemAmount}"
/>
<h:inputText id="shipmentItemAmount"
disabled ="false"
required ="true"
value="#{shipmentItemController.shipmentItemUI.value.amount}"
label="#{shipmentBundle.shipmentItemAmount}"
size="4" >
<f:validateLongRange minimum="1"/>
</h:inputText>
<h:outputText value="#{coreBundle.requiredChar} #{shipmentBundle.shipmentItemNeedsCooling}"
/>
<h:selectBooleanCheckbox id="shipmentItemNeedsCooling"
disabled ="false"
required ="true"
value="#{shipmentItemController.shipmentItemUI.value.needsCooling}"
label="#{shipmentBundle.shipmentItemNeedsCooling}"
/>
<h:outputText for="shipmentItemDetails"
value="#{shipmentBundle.shipmentItemDetails}"
/>
<h:inputTextarea id="shipmentItemDetails"
disabled ="false"
required ="true"
value="#{shipmentItemController.shipmentItemUI.value.details}"
label="#{shipmentBundle.shipmentItemDetails}"
cols="38"
rows="5"
/>
</h:panelGrid>
<h:panelGrid columns="1" dir="LTR">
<h:panelGrid columns="2" dir="LTR">
<a4j:commandButton value="#{coreBundle.acceptButton}"
action="#{shipmentItemController.onUpdate()}"
render="shipmentItemsTable">
</a4j:commandButton>
<h:commandLink value="#{coreBundle.closeLink}"
immediate="true">
<rich:componentControl target="shipmentItemUpdateDialog" operation="hide" />
</h:commandLink>
</h:panelGrid>
<h:outputText value="#{coreBundle.requiredText}"/>
</h:panelGrid>
</rich:popupPanel>
</h:form>
I hope this helps.
I think you got it right.. think of the pop-up as a regular page. To submit and close the pop-up, do something like this:
<a4j:commandButton value="Save" onclick="#{rich:component('panelId}.hide();" render="..."/>
Hope this helps..
I'm developing this project using JSF 2.0, NetBeans 6.9.1, GlassFish 3.1, Mojarra 2.0.3, and PrimeFaces 2.2-RC2.
My question is similar to this question, but even though I was able to make one of my buttons work, the other one does not. Here's my situation: I have a dataTable with a column containing two links, one to edit line data, one to view line data. Clicking either the "Edit" or "View" link takes you to a detail page with <h:panelGrid> components inside <p:tabView> components. My detail page has two <p:tabView> components, one for editing, one for just viewing data. Which one you see depends on the <c:if> statements. The button in the first <p:tabView> on the page (by that I mean first working your way down from the top) works as I would like it to, this happens to be the "Edit" component. The button in the other <p:tabView> does not work. I set up break points and went through the debugger, the second button doesn't seem to fire an ActionEvent regardless of what I try. Here's my code for the page:
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{userDetailBean.selectedUserId}" />
<f:viewParam name="action" value="#{userDetailBean.view}" />
</f:metadata>
</ui:define>
<ui:define name="main_base_content_top">
<h:form>
<p:toolbar>
<p:toolbarGroup align="left">
<h:commandButton value="Return to User List" action="user_grid" />
</p:toolbarGroup>
</p:toolbar>
</h:form>
</ui:define>
<ui:define name="main_base_content">
<c:if test="#{empty userDetailBean.view}">
<h:form>
<table align="center">
<tr>
<td>
<p:tabView>
<p:tab title="#{msgs.UserDetailTabTitle}">
<h:panelGrid columns="4">
<h:outputLabel value="#{msgs.UserDetailFirstName}" for="fname" />
<h:inputText id="fname" value="#{userDetailBean.firstName}" />
<h:outputLabel value="#{msgs.UserDetailJobTitle}" for="jtitle" />
<h:inputText id="jtitle" value="#{userDetailBean.jobTitle}" />
<h:outputLabel value="#{msgs.UserDetailLastName}" for="lname" />
<h:inputText id="lname" value="#{userDetailBean.lastName}" />
<h:outputLabel value="#{msgs.UserDetailEmployeeId}" for="empid" />
<h:inputText id="empid" value="#{userDetailBean.id}" />
<h:outputLabel value="#{msgs.UserDetailDateOfHire}" for="doh" />
<h:inputText id="doh" value="#{userDetailBean.DOH}" />
<h:outputLabel value="#{msgs.UserDetailLocation}" for="location" />
<h:inputText id="location" value="#{userDetailBean.location}" />
<h:outputLabel value="#{msgs.UserDetailStatus}" for="status" />
<h:inputText id="status" value="#{userDetailBean.status}" />
<h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden />
<h:outputLabel value="#{msgs.UserDetailComments}" for="comments" />
<h:inputTextarea id="comments" value="#{userDetailBean.comments}" />
<h:inputHidden />
<p:commandButton ajax="false" action="#{userDetailBean.submitChanges()}" value="Submit Changes" />
</h:panelGrid>
</p:tab>
</p:tabView>
</td>
</tr>
</table>
</h:form>
</c:if>
<c:if test="#{! empty userDetailBean.view}">
<h:form>
<table align="center">
<tr>
<td>
<p:tabView>
<p:tab title="#{msgs.UserDetailViewTabTitle}">
<h:panelGrid columns="4">
<h:outputLabel value="#{msgs.UserDetailFirstName}" for="fname" />
<h:outputText id="fname" value="#{userGridBean.selectedUser.firstName}" />
<h:outputLabel value="#{msgs.UserDetailJobTitle}" for="jtitle" />
<h:outputText id="jtitle" value="#{userGridBean.selectedUser.jobTitle}" />
<h:outputLabel value="#{msgs.UserDetailLastName}" for="lname" />
<h:outputText id="lname" value="#{userGridBean.selectedUser.lastName}" />
<h:outputLabel value="#{msgs.UserDetailEmployeeId}" for="empid" />
<h:outputText id="empid" value="#{userGridBean.selectedUser.id}" />
<h:outputLabel value="#{msgs.UserDetailDateOfHire}" for="doh" />
<h:outputText id="doh" value="#{userGridBean.selectedUser.DOH}" />
<h:outputLabel value="#{msgs.UserDetailLocation}" for="location" />
<h:outputText id="location" value="#{userGridBean.selectedUser.location}" />
<h:outputLabel value="#{msgs.UserDetailStatus}" for="status" />
<h:outputText id="status" value="#{userGridBean.selectedUser.status}" />
<h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden /> <h:inputHidden />
<h:outputLabel value="#{msgs.UserDetailComments}" for="comments" />
<h:outputText id="comments" value="#{userGridBean.selectedUser.comments}" />
<h:inputHidden /> <h:inputHidden /> <h:inputHidden />
<p:commandButton onclick="submit()" ajax="false" action="#{userDetailBean.navigation()}" value="Retur to User Grid" />
</h:panelGrid>
</p:tab>
</p:tabView>
</td>
</tr>
</table>
</h:form>
</c:if>
</ui:define>
</ui:composition>
</body>
I've tried everything I can think of for the second button: ajax="false"; onclick="submit()"; ajax="false" onclick="submit"; I've tried implicit navigation with a redirect as well as a navigation rule with a redirect. The action methods userDetailBean.submitChanges() and userDetailBean.navigate() both return the same string, which corresponds to a navigation rule in my faces-config file. The submitChanges method gets called, but my navigate method does not. I'm not filling the fields with any data at this point, I'm just trying to get the basic navigation to work. Why isn't my commandButton on the second tabView working?
Another reason that a commandbutton isn't been invoked is that the rendered attribute of the button or one of its parents evaluated false during apply request values phase of the form submit.
You have actually none, but those <c:if> tags does similar thing, only during view build time instead of view render time. The view params are not applied during building the view, but only thereafter. That's exactly why #{userDetailBean.view} is always empty.
I have never used such a construct with <c:if>, but I've had similar views like this where this all just works with a #ViewScoped bean where the rendering property is been applied on a fullworthy JSF component instead of <c:if>.
As first step, get rid of <c:if>s and move their tests into rendered attribute of the <h:form>s they are wrapping:
<h:form rendered="#{empty userDetailBean.view}">
...
</h:form>
<h:form rendered="#{not empty userDetailBean.view}">
...
</h:form>
If in vain (I guess that this will fail because you aren't using ajax and the viewparams are not preserved) and the bean is indeed #RequestScoped, then you need to mark it #ViewScoped to preserve the rendering conditions.
Related questions:
JSF h:commandLink is not being invoked
Unrelated to the problem, I'd rather use <h:panelGroup /> instead of <h:inputHidden /> to "fill" the empty cells of the table. They are cheaper to encode and decode and also ends in better HTML.