I'm new to jsf, and I'm writing my first application using richfaces. I'm having trouble with the ajax tag that I use to update the associated managed bean property on server for rich:calendar components. This is the code:
<rich:panel header="Computing Options">
<h4>Time Interval</h4>
<h:panelGrid columns="4" width="100%">
<h:outputText value="From" />
<rich:calendar id="intervalFrom" value="#{scenarioEditor.intervalFrom}" popup="true" showApplyButton="true" datePattern="yyy-MM-ddTHH:mm">
<a4j:ajax execute="#this" event="change" render="outFrom" />
</rich:calendar>
<h:outputText value="To" />
<rich:calendar id="intervalTo" value="#{scenarioEditor.intervalTo}" popup="true" showApplyButton="true" datePattern="yyy-MM-ddTHH:mm">
<a4j:ajax execute="#this" event="change" render="outTo" />
</rich:calendar>
<h:outputText id="outFrom" value="From: #{scenarioEditor.intervalFrom}" />
<h:outputText id="outTo" value="To: #{scenarioEditor.intervalTo}" />
</h:panelGrid>
<h4>Algorithms</h4>
<h:panelGrid columns="2">
<h:selectBooleanCheckbox value="#{scenarioEditor.visibilityClashes}" id="clash" >
<f:ajax execute="#this"/>
</h:selectBooleanCheckbox>
<h:outputLabel value="Visibility Clashes Evaluator" for="clash" style="width:170px" />
<h:selectBooleanCheckbox value="#{scenarioEditor.xBandInterference}" id="xband" >
<f:ajax execute="#this"/>
</h:selectBooleanCheckbox>
<h:outputLabel value="X-Band Interferences Evaluator" for="xband" style="width:170px"/>
</h:panelGrid>
</rich:panel>
checkboxes works fine, but the calendars do not. Why? I`ve tried both f:ajax and a4j:ajax without luck.
To better clarify, I want that right after the user has finished entering a value into the calendar, an ajax request is made that call the setter method for the associated property. And this, for the calendar does not happen while for the checkboxes, it does.
The ajax event is failing because of T in datePattern="yyy-MM-ddTHH:mm" is not a valid date formatting pattern. If you add a <rich:messages/> component to your field, you'll see that a conversion error is occurring on each ajax request. Remove the T and you'll be fine
Related
In testing the validateOrder validator in OmniFaces 1.8.1, it seems that the validator is not applied to components when used in conjunction with a Primefaces commandButton that partially submits components based on a PrimeFaces Selector (PFS). A sample is below, which is a stripped-down, but representative, test case of my app's usage.
<h:body>
<h:form>
<p:commandButton value="Show" action="#{testBean.save}" oncomplete="PF('testDialogJS').show()"/>
</h:form>
<p:dialog header="Test Dialog" widgetVar="testDialogJS" resizable="false" closeOnEscape="false" closable="false" modal="true" dynamic="true">
<h:form>
<p:tabView>
<p:tab title="Tab 1">
<p:panel header="Tab 1 Panel" styleClass="tab1Panel">
<p:outputLabel value="Test 1"/>
</p:panel>
</p:tab>
<p:tab title="Tab 2">
<p:panel header="Tab 2 Panel" styleClass="tab2Panel">
<h:panelGrid columns="2">
<p:outputLabel for="startDate" value="Start Date: "/>
<h:panelGroup>
<p:calendar id="startDate" value="#{testBean.startDate}" navigator="true" pattern="M/d/yyyy"
required="true" requiredMessage="Start Date is required"/>
<p:message for="startDate"/>
</h:panelGroup>
<p:outputLabel for="endDate" value="End Date: "/>
<h:panelGroup>
<p:calendar id="endDate" value="#{testBean.endDate}" navigator="true" pattern="M/d/yyyy"
required="true" requiredMessage="End Date is required"/>
<p:message for="endDate"/>
<o:validateOrder id="campaignDateRangeValidator" components="startDate endDate" message="Start Date must be before End Date"/>
<p:message for="campaignDateRangeValidator"/>
</h:panelGroup>
</h:panelGrid>
</p:panel>
</p:tab>
</p:tabView>
<p:commandButton value="Save" action="#{testBean.save}"
process="#form" update="#form"
oncomplete="if (!args.validationFailed) { PF('testDialogJS').hide(); }"/>
</h:form>
</p:dialog>
</h:body>
Setting the start date to, say, 10/1/2014, and the end date to 9/30/2014, then clicking the save button, the validator error message is properly displayed. However, if the commandButton's process attribute is set to #(.tab2Panel :input) #this, the validator is never called in code. I breakpointed in ValidateOrder's validateValues method - it's never called. And thus, the action is allowed to proceed.
Looking at the AJAX XHR, javax.faces.partial.execute is set to the component ID of the form in the passing case, while it's set to the explicit list of individual field component IDs to bind in the failing case (without the component ID of the form).
Is this a bug? Unsupported? etc? If unsupported, any suggestions on how to handle this desired usage? Thanks!
The OmniFaces multi-field validators are designed as UI components, because it's among others otherwise not possible to get multi-field validation to work inside e.g. a <h:dataTable>. On contrary to standard JSF validators such as <f:validator>, which are basically taghandlers, the <o:validateOrder> component must therefore also be covered in the process attribute of <p:commandButton> (and equivalently also in execute attribute of <f:ajax>).
Your best bet is to explicitly process the entire tab instead of only the tab's input components. E.g.
<p:tabView id="tabs">
<p:tab id="tab2">
...
</p:tab>
</p:tabView>
<p:commandButton ... process="#this tabs:tab2" />
I am trying to update a selectOneMenu from the results of another selectOneMenu.
When group is selected the user menu should be updated.
I have verified that the data for the user menu is being updated. It is not being rendered however.
Currently running Primefaces 3.4.2 and JSF 2.1
<ui:composition>
<br/><br/>
<h:form id="transferForm">
<h:panelGrid columns="1" style="width: 500px;margin: auto;text-align: center" >
<h:panelGroup>
<h:outputLabel for="group" value="Group" />
<h:selectOneMenu id="group" value="#{projectBean.transferUtil.selectedTransferGroup}" >
<f:selectItems value="#{projectBean.transferUtil.transferGroups}" />
<f:ajax execute="group" render="user" />
</h:selectOneMenu>
<br />
<h:outputLabel for="user" value="User" />
<h:selectOneMenu id="user" value="#{projectBean.transferUtil.selectedTransferUser}" required="true" requiredMessage="Select User" >
<f:selectItems value="#{projectBean.transferUtil.transferUsers}" />
</h:selectOneMenu>
</h:panelGroup>
<p:commandButton id="projectTransferButton" action="#{projectBean.transferUtil.transfer}" value="Transfer" update=":projtabs,:growlForm:growlMesg">
<f:setPropertyActionListener target="#{projectBean.activeTab}" value="#{projectBean.project_tab_index}" />
</p:commandButton>
</h:panelGrid>
</h:form>
<br/><br/>
[EDIT]
Alright this is the error I am getting.
<?xml version='1.0' encoding='UTF-8'?>
<partial-response><error><error-name>class java.lang.IllegalArgumentException</error-name><error-message><![CDATA[rss02.1 OPERA]]></error-message></error></partial-response>
And this is the code in question.
<p:dataGrid var="area" value="#{projectBean.projectUtil.project.rssAreas}" columns="1">
<p:column>
<h:selectBooleanCheckbox id="rss#{area.shortName}" label="#{area.name}" value="#{area.active}" />
<h:outputText value="#{area.name}" />
</p:column>
</p:dataGrid>
You should not perform business logic in getters/setters. They are invoked multiple times in JSF lifecycle and are intented to get and set the property. You should perform business logic in action(listener) methods instead.
The following construct should work:
<h:selectOneMenu id="group" value="#{projectBean.transferUtil.selectedTransferGroup}" >
<f:selectItems value="#{projectBean.transferUtil.transferGroups}" />
<f:ajax execute="group" listener="#{projectBean.transferGroupChanged}" render="user" />
</h:selectOneMenu>
<h:selectOneMenu id="user" value="#{projectBean.transferUtil.selectedTransferUser}" required="true" requiredMessage="Select User" >
<f:selectItems value="#{projectBean.transferUtil.transferUsers}" />
</h:selectOneMenu>
With
public void transferGroupChanged(AjaxBehaviorEvent event) {
// Change the transferUsers here.
}
The getters and setters should not contain any business logic. They should merely get and set the property.
See also:
Why JSF calls getters multiple times
How to load and display dependent h:selectOneMenu on change of a h:selectOneMenu
The text with id=txt is inserted outside the commandlink after rerendering.
And therefore the link is broken. A refresh of the page gets it back.
Could somebody please help?
<h:form id="frm">
<h:selectOneMenu value="#{myBean.currentId}">
<f:selectItems value="#{myBean.selectListA}" />
<a4j:support event="onchange" action="#{myBean.changeSomething}"
reRender="priceGroup,idLink" />
</h:selectOneMenu>
<h:panelGroup id="priceGroup">
<a4j:commandLink id="idLink">
<h:outputText id="txt" value="#{myBean.someValue}" />
</a4j:commandLink>
</h:panelGroup>
</h:form>
The selectBooleanCheckbox ajax event fires but the listener is never executed.
If I remove the c:forEach and just call the first one in the list it works.
<p:selectBooleanCheckbox value="#{Controller.graphFilter.get(0).checked}" >
<p:ajax listener="#{Controller.addMessage}" />
</p:selectBooleanCheckbox>
notes:
graphFilter is a list where container has the sets/gets for checked and description.
controller is a viewscoped managed bean.
addMessage public function that puts a message for the growl.
Everything is in the same form.
<h:form id="form" prependId="false">
<p:growl id="growl" showDetail="true"/>
<c:forEach items="#{Controller.graphFilter}" var="Gc">
<h:outputText value="#{Gc.description}" />
<p:selectBooleanCheckbox value="#{Gc.checked}" >
<p:ajax listener="#{Controller.addMessage}"/>
</p:selectBooleanCheckbox>
</c:forEach>
</h:form>
You should wrap your components with a p:column:
<p:column>
<h:outputText value="#{Gc.description}" />
<p:selectBooleanCheckbox value="#{Gc.checked}" >
<p:ajax listener="#{Controller.addMessage}"/>
</p:selectBooleanCheckbox>
</p:column>
But replacing the whole structure with a p:dataList would be more elegant.
I am building an invoice application. When the user selects the client, then the services associated with the client are re-rendered in a dataTable by an ajax event. But, the ajax event of the selectOneMenu in the dataTable does not fire.
This is the form which lets the user select a client:
<h:form>
<h:selectOneMenu id="clientSelect" value="#{invoiceBean.client}">
<f:ajax execute="clientSelect" listener="#{invoiceServiceListener.processClientValueChange}" render=":test :invoiceData"/>
<f:selectItems value="#{invoiceBean.clientOptions}"/>
</h:selectOneMenu>
</h:form>
This will fire an ajax event which fills the services array in the invoiceBean and re-renders the dataTable which displays the services in another selectOneMenu in the dataTable. This part works properly.
This is the datatable that is re-rendered after selecting the client by the above form:
<h:panelGroup id="test">
<h:dataTable id="invoiceData" value="#{attributes.priceAttributes}" var="loop">
<h:column>
<ui:param name="service" value="service#{loop}" />
<ui:param name="description" value="description#{loop}" />
<ui:param name="price" value="price#{loop}" />
<h:form id="invoiceSelectMenu">
<h:selectOneMenu id="selectMenu" value="#{invoiceBean[service]}">
<f:ajax event="change" execute="selectMenu" listener="#{invoiceServiceListener.procesServiceValueChange}" render="#form" />
<f:attribute name="row" value="#{loop}" />
<f:selectItems value="#{invoiceBean.services}" />
</h:selectOneMenu>
<h:inputText id="description" value="#{invoiceBean[description]}" />
<h:inputText id="price" value="#{invoiceBean[price]}" />
<h:outputText value="#{loop}" />
</h:form>
</h:column>
</h:dataTable>
</h:panelGroup>
The selectOneMenu is filled properly. However, the ajax event in this select one menu does not work after it has been re-rendered by the first form. But, if I manually fill the services array without submitting the first form, then this ajax event executes normally. By the way, this ajax event also sets a value to the description and price input fields, which should be re-rendered when the event happens. The invoiceBean is request scoped.
This is going to be tricky. Due to JSF spec issue 790, whenever you re-render some content containing another <h:form> using <f:ajax>, then its view state will get lost. To solve this, you'd basically need to reference the full client ID of another <h:form> inside <f:ajax> instead of some containing component. But you've basically multiple forms inside a <h:dataTable> which can't be referenced by an absolute client ID.
You'd need to rearrange the code to put the <h:form> outside the <h:dataTable> and change the <f:ajax> to execute only the necessary components.
<h:form id="invoiceDataForm">
<h:dataTable id="invoiceData" value="#{attributes.priceAttributes}" var="loop">
<h:column>
<ui:param name="service" value="service#{loop}" />
<ui:param name="description" value="description#{loop}" />
<ui:param name="price" value="price#{loop}" />
<h:selectOneMenu id="selectMenu" value="#{invoiceBean[service]}">
<f:ajax execute="selectMenu,description,price" listener="#{invoiceServiceListener.procesServiceValueChange}" render="#form" />
<f:attribute name="row" value="#{loop}" />
<f:selectItems value="#{invoiceBean.services}" />
</h:selectOneMenu>
<h:inputText id="description" value="#{invoiceBean[description]}" />
<h:inputText id="price" value="#{invoiceBean[price]}" />
<h:outputText value="#{loop}" />
</h:column>
</h:dataTable>
</h:panelGroup>
and then reference it form the first form as follows:
<f:ajax execute="clientSelect" listener="#{invoiceServiceListener.processClientValueChange}" render=":invoiceDataForm" />
Note that some component libraries such as PrimeFaces have already workarounded/solved this in the component library specific ajax engine. So if it might happen that you're already using PrimeFaces, you could also replace <f:ajax> of the first form by <p:ajax>.
Unrelated to the concrete problem, the <f:attribute name="row" value="#{loop}" /> may not do what you expect it does. It will set null because <f:xxx> tags run during view build time, not during view render time tag. The #{loop} is not available during view build time. But that's subject for a different question :)