Richfaces 4 bug in datatable with datascroller validation when empty - validation

I have a screen in my Richfaces application which uses a datatable and datascroller, with validation to ensure that data is filled.
( example to simulate the problem, full example can be found here
<h:form id="articleForm" >
<h:panelGroup layout="block">
<rich:messages globalOnly="true" />
<rich:dataTable value="#{productModifyBean.articles}" var="article" id="articleTable"
rows="15" >
<rich:column headerClass="headerOverflow artNrColumn">
<f:facet name="header">
<h:outputText value="articleNumber" />
</f:facet>
<h:outputText value="#{article.articleNumber}"/>
</rich:column>
<rich:column headerClass="headerOverflow shortNameColumn">
<f:facet name="header">
<h:outputText value="Name" />
</f:facet>
<h:outputText value="#{article.shortName}" />
</rich:column>
<rich:column headerClass="headerOverflow quantityColumn" >
<f:facet name="header">
<h:outputText value="Quantity" />
</f:facet>
<h:inputText value="#{article.quantity}" required="true"
requiredMessage="This is required" converterMessage="Error conversion"
id="modifyArticleFormatQuantity" >
</h:inputText>
<rich:message for="modifyArticleFormatQuantity" errorClass="errorColorRed" />
</rich:column>
</rich:dataTable>
<rich:dataScroller for="articleTable" renderIfSinglePage="false" boundaryControls="show" fastControls="hide" execute="#form" render="articleTable"
stepControls="show" style="float:right;" />
</h:panelGroup>
<br style="clear: both" />
<br style="clear: both" />
<div align="right" style="clear: both">
<a4j:commandButton value="#{msgs['button.modify'] }" styleClass="submitButton"
render="#{facesContext.validationFailed ? '#none' : 'articleForm'}"
actionListener="#{productModifyBean.modifyProduct}">
</a4j:commandButton>
</div>
</h:form>
Data validation should happen when the user presses the submit button ( to save the data) , and when the user using the pagination to go to a different page.
When clicking the submit button after leaving one field empty, the behaviour is normal : it shows an empty field with the remark 'this is required'
However, when instead moving to a different page ( for example clicking on the '2' page button ) , validation happens correctly, but the old value is put back into the screen, thus stating that the value should be filled but showing it filled in with a value.
Anyone have any idea what the reason for this problem could be, and how to resolve it ? Is this a bug in RichFaces, or am I overlooking something ?

I found the solution by trial and error :
If I change the datascroller to use render="#region" , the screen is correctly rendered.
<rich:dataScroller for="articleTable" renderIfSinglePage="false" boundaryControls="show" fastControls="hide" execute="#form" render="articleTable"
stepControls="show" style="float:right;" />

Related

<p:commandButton> won't submit form on first click if <p:inputText> field uses <p:ajax>

I'm having an issue with the following form:
<h:form>
<p:outputPanel autoUpdate="true">
<p:panelGrid columns="2">
<f:facet name="header">
<h:outputText value="Edit a Recycler"/>
</f:facet>
<p:outputLabel value="Recycler Name" for="recyclerName"/>
<p:inputText id="recyclerName" value="#{RecyclerAdmin.editItem.company.companyName}" required="true" requiredMessage="You must name the recycler.">
<p:ajax async="true" />
</p:inputText>
<p:outputLabel value="Zip Code" for="zipCode"/>
<p:inputText id="zipCode" value="#{RecyclerAdmin.editItem.company.primaryAddressId.zip}" required="false">
<p:ajax event="blur" async="true" update="citystate" listener="#{RecyclerAdmin.zipCodeChanged}"/>
</p:inputText>
<p:outputLabel value="City/State"/>
<c:choose>
<c:when test="${RecyclerAdmin.editItem.company.primaryAddressId.city != null and RecyclerAdmin.editItem.company.primaryAddressId.city.length() > 0}">
<h:outputText id="citystate" value="#{RecyclerAdmin.editItem.company.primaryAddressId.city}, #{RecyclerAdmin.editItem.company.primaryAddressId.state}"/>
</c:when>
<c:otherwise>
<p:spacer id="citystate"/>
</c:otherwise>
</c:choose>
<f:facet name="footer">
<p:commandButton id="updatebutton" action="#{RecyclerAdmin.update()}" value="Save" ajax="false"/>
<p:commandButton id="cancelbutton" action="#{RecyclerAdmin.cancel}" value="Cancel" ajax="false" immediate="true"/>
</f:facet>
</p:panelGrid>
</p:outputPanel>
</h:form>
If I make a change to the "Recycler Name" text field, and then immediately click on the save button, the button click highlighting activates, and remains active, but the form does not submit until the button is clicked a second time. If I click somewhere else before clicking on the save button, everything works, and if I remove the ajax async="true" from the recyclerName field, the form also will submit normally, but I need the ajax reference otherwise any changed values in the field are erased when the zipCode field is manipulated.
Any ideas?
The problem was caused by the outputPanel autoUpdate="true" tag. i have added specific update field references to the individual ajax tags and the problem is now gone.
try different event
try removing async=true
p:ajax event="keyup"
http://www.primefaces.org/showcase/ui/ajax/event.xhtml

Richfaces datatable not refreshing a column after sorting

I have a datatable with custom sorting. It sorts the array containing my data and then the table is refreshed via ajax call. The table has multiple columns with simple text in it, and an additional column with command button and command links. My problem is, that this buttons and links are not refreshed. It means that if I click the button on the second row, it affects the element which was in the second row before sorting.
This is the page code:
<h:body>
<h:form class="page_frame">
<a4j:jsFunction name="sortTable" render="data_table#body"
actionListener="#{MyBean.getFilteredData()}" >
<a4j:param name="param1" assignTo="#{MyBean.newSortBenchmark}"/>
</a4j:jsFunction>
<rich:dataTable value="#{MyBean.getFilteredData()}" var="data" id="data_table"
rowClasses="odd-row, even-row" styleClass="even_odd"
style="width: 900px;">
<rich:column >
<f:facet name="header">
<span onclick="sortTable('name')">Name</span><br/>
</f:facet>
<h:outputText value="#{data.name}"/>
</rich:column>
//more similar columns with sorting
<rich:column>
<f:facet name="header">Start/Stop</f:facet>
<a4j:commandButton value="Start" action="#{MyBean.startProcess(data)}"
rendered="#{!data.processRunning}"
render="data_table#body"
execute="#this" style="width: 100%" >
</a4j:commandButton>
<a4j:commandButton value="Stop" action="#{MyBean.stopProcess(data)}"
rendered="#{data.processRunning}"
render="data_table#body"
execute="#this" style="width: 100%" >
</a4j:commandButton>
</rich:column>
<rich:column>
<f:facet name="header">Actions</f:facet>
<a4j:region>
<a4j:commandLink action="#{MyBean.showDetails(data)}" oncomplete="#{rich:component('detailsPanel')}.show()" render="details_table" >
<h:graphicImage id="details_image" name="details.png" library="images" style="border:0" />
<rich:tooltip followMouse="true" target="details_image" value="Details" />
</a4j:commandLink>
</a4j:region>
//more similar command links, also not working
</rich:column>
</rich:dataTable>
</h:form>
</h:body>
And the filtering is done by:
Collections.sort(dataList, new dataComparator(sortBenchmark));

Update the JSF bean even if the validation fails?

JSF beans are generally not updated when the validation fails, which in some cases causes really ugly effects, for example, when using facet="output" of p:inplace:
<h:form>
<h:panelGrid id="panel" columns="3" cellpadding="2">
<p:outputLabel value="My Field" for="myfield" />
<p:inputText id="myfield" value="#{test.myField}" required="true" />
<p:message for="myfield" />
<h:outputText value="Checkbox: " />
<p:inplace id="checkboxInplace" effect="none">
<f:facet name="output">#{test.myBooleanText}</f:facet>
<f:facet name="input">
<h:selectBooleanCheckbox value="#{test.myBoolean}" />
</f:facet>
</p:inplace>
<p:spacer />
</h:panelGrid>
<p:commandButton id="refresh" icon="ui-icon-refresh" update="panel" process="#form"/>
</h:form>
The output facet defines the inplace labels, which should be localized instead of standard ones:
private boolean myBoolean;
public String getMyBooleanText() {
return myBoolean ? "Ja" : "Nein";
}
However, when the validation fails, the inplace output facet shows the old value of the checkbox, not the actual one. If you click on it, a real value is shown.
How to solve that issue and actualize the output correctly? Submiting the values to the bean would be the best, because I have no problem with consistent state of values on the client and server, as long no action is actually executed (asserted by the validation).
Haven't tried it myself, but give this a chance:
<p:inplace id="checkboxInplace" effect="none">
<f:facet name="output">#{test.myBoolean ? 'Ja' : 'Nein'}</f:facet>
<f:facet name="input">
<h:selectBooleanCheckbox value="#{test.myBoolean}" immediate="true">
<p:ajax update="#parent" />
<h:selectBooleanCheckbox />
</f:facet>
</p:inplace>

Some labels for input fields with invalid input turn red some don't

I have a bunch of input fields in a JSF form with associated labels and validators.
On some fields a failing validation turns the label red on some it doesn't.
Any idea where the cause for that might be, or how to debug that?
I verified that the lable/input relationship is set up properly by clicking the label and observing that the focus goes to the respective input field.
We use JSF-2.0 and Primefaces 5
This one turns red:
<p:column style="width:10em;">
<f:facet name="header">
<span
title="#{messages['tooltip.model.modelSearch.modelKeyPattern']}">
<p:outputPanel>
<p:outputLabel
id="modelKeyPatternLabel"
for="modelKeyPattern"
styleClass="control-label"
value="#{messages['label.model.modelSearch.modelKey']}" />
<p:inputText
id="modelKeyPattern"
value="#{modelSearchBean.modelKeyPattern}"
validatorMessage="#{messages['error.model.modelSearch.modelKey']}"
size="6"
styleClass="searchField">
<f:validateLength maximum="6" />
</p:inputText>
</p:outputPanel>
</span>
</f:facet>
This one doesn't:
<p:column style="width:6em;">
<f:facet name="header">
<span
title="#{messages['tooltip.model.modelSearch.modelYear']}">
<p:outputPanel>
<h:outputLabel
id="modelYearLabel"
for="modelYear"
styleClass="control-label"
value="#{messages['label.model.modelSearch.table.column.modelYear']}" />
<p:inputText
id="modelYear"
value="#{modelSearchBean.modelYear}"
validator="#{modelYeaValidator.validate}"
styleClass="searchField"
size="4">
</p:inputText>
</p:outputPanel>
</span>
</f:facet>
<h:outputText value="#{model.modelYear}" />
</p:column>
Found it. The red label is a h:outputLabel while the other one is a p:outputLabel. Note the difference between p: and h:

Primefaces update from inside another form

I'm not sure what's wrong with my HTML code. From what I read, it should work. I even tried using prependId="false" which didn't resolve the problem of not finding the UI Component.
<p:tabView>
<p:tab title="Tab1" id="tab1">
<h:form id="form1" prependId="false">
<p:panelGrid columns="2" id="grid1">
<h:outputLabel for="minDraw" value="Starting draw number:" />
<p:inputText id="minDraw" value="#{LottoMaxBacking.minDraw}" />
<p:commandButton value="Get Frequency From Begining"
actionListener="#{LottoMaxBacking.loadAllDrawFreq}"
update=":form2:freqTable" />
</p:panelGrid>
</h:form>
<h:form id="form2" prependId="false">
<p:dataTable var="entry" value="#{LottoMaxBacking.drawFreqList}"
id="freqTable">
<f:facet name="header">
<h:outputText value="#{LottoMaxBacking.tableHeader}" />
</f:facet>
<p:column sortBy="#{entry.key}" headerText="Ball Number">
<h:outputText value="#{entry.key}" />
</p:column>
<p:column sortBy="#{entry.value}" headerText="Frequency">
<h:outputText value="#{entry.value}" />
</p:column>
</p:dataTable>
</h:form>
</p:tab>
<p:tab title="Tab 2"></p:tab>
</p:tabView>
I tried ":tab1:form2:freqTable", ":freqTable", and "freqTable" but none of them work. When I put both forms together as a single form, it would find the freqTable fine.
OK I finally figured it out after looking at the error message again.
Cannot find component with identifier ":form2:freqTable" referenced from "j_idt54:j_idt56"
idt54 refers to the TabView and idt56 refers to the command button. So it turns out that my button's AJAX update string didn't go far enough original and all my other attempts referred to the wrong parent container. I added an id to p:tabView and changed the update String and it worked.
<p:commandButton value="Get Frequency From Begining"
actionListener="#{LottoMaxBacking.loadAllDrawFreq}"
update="tv:form2:freqTable" />

Resources