I've encountered an issue upgrading from PrimeFace 8 to PrimeFaces 11 when including a required text input inside of a p:rowExpander (itself inside of a p:dataTable) that is expanded via satisfying the EL condition given by the p:dataTable's expandedRow attribute.
Expected behavior: When intentionally not supplying a value for the required text input and submitting the form via p:commandButton click, I expect to see "text input failed validation: text input required" messaging.
Observed behavior: On the first click of the p:commandButton, nothing happens on the page. Via browser console, I can see that there is a network request and response, but again, on the page there is no observable change. Clicking the p:commandButton a second time yields the expected "text input failed validation: text input required" messaging in the view. If you remove the expandedRow attribute and manually expand the row, the bug does not occur (i.e. the input validation fails as expected on the first click, making the expandedRow attribute suspect). If it's helpful, this issue does not present itself with PrimeFaces 8.
I'm running Wildfly 23, JSF 2.3, Java 11. The issue appears to affect all browsers I've tested, to include Firefox and Chrome.
I've submitted a defect report and two reproducer projects here:
https://github.com/primefaces/primefaces/issues/8310
For the interested reader, I've recently amended the defect report above to include the finding that the "no response on first click" UI validation bug can also be made to go away depending on the placement of the h:form (while retaining the expandedRow attribute EL expression). If the h:form is included on the outside of the p:dataTable component, the bug occurs as reported. If the h:form is placed inside the p:rowExpander, the UI validation works as expected (i.e. on the first click of the p:commandButton). The reproducer project primefaces-rowexpansion-bug-simple.tar.gz (available at the GitHub link above) demonstrates this. The test.xhtml view file for the example is shown below
Can anyone explain why the placement of the h:form would cause things to work this way? The affected view in my project has a combination of related UI inputs that span a row in the datatable and also "live" outside the datatable, so there isn't an immediately obvious way that I see to refactor things to replace the outer form with an form inside the p:rowExpander. Thank you in advance for any input you might have.
Best regards,
-Andy
***
Code: Select all
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>PrimeFaces Test</title>
<h:outputScript name="test.js" />
</h:head>
<h:body>
<h1>#{testView.string}</h1>
<p:growl />
<h2>Outer form - UI validation fails on first click</h2>
<h:form>
<p:dataTable value="#{testView.stringList}"
lazy="false"
var="c"
rowKey="#{c}"
expandedRow="#{c eq 'Data2'}">
<p:column styleClass="Wid20px" exportable="false">
<p:rowToggler />
</p:column>
<p:column styleClass="Wid10" sortBy="#{c}" headerText="Data">
<h:outputText value="#{c}"/>
</p:column>
<p:rowExpansion>
<p:inputTextarea id="text-input"
value="#{testView.textInput}"
required="#{c eq 'Data2'}"/>
<p:message for="text-input" />
<h:panelGroup>
<p:commandButton value="Update" process="@form" update="@form" action="#{testView.updateTextInput}"/>
<h:panelGroup>
<h:outputText rendered="#{!empty testView.message}" value="#{testView.message}" />
</h:panelGroup>
</h:panelGroup>
</p:rowExpansion>
</p:dataTable>
</h:form>
<h2>Inner form - UI validation works on first click</h2>
<p:dataTable value="#{testView.stringList}"
lazy="false"
var="c"
rowKey="#{c}"
expandedRow="#{c eq 'Data2'}">
<p:column styleClass="Wid20px" exportable="false">
<p:rowToggler />
</p:column>
<p:column styleClass="Wid10" sortBy="#{c}" headerText="Data">
<h:outputText value="#{c}"/>
</p:column>
<p:rowExpansion>
<h:form>
<p:inputTextarea id="text-input"
value="#{testView.textInput}"
required="#{c eq 'Data2'}"/>
<p:message for="text-input" />
<h:panelGroup>
<p:commandButton value="Update" process="@form" update="@form" action="#{testView.updateTextInput}"/>
<h:panelGroup>
<h:outputText rendered="#{!empty testView.message}" value="#{testView.message}" />
</h:panelGroup>
</h:panelGroup>
</h:form>
</p:rowExpansion>
</p:dataTable>
</h:body>
</html>