PrimeFaces DataTable置于表单外时提交非AJAX表单导致选中字段被置为null的版本差异问题及行为合理性咨询
Let's break down this behavior change in PrimeFaces and address your questions clearly:
Observed Behavior
When placing a <p:dataTable> outside an <h:form> and submitting a non-AJAX form, the view field bound to the selection attribute (like DtView.selectedEntry in your example) gets reset to null. This happens consistently in PrimeFaces 10.0.1 and newer versions, but in 10.0.0 and 8.x releases, the selected value remains unchanged.
Example Code
XHTML
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:p="http://primefaces.org/ui" xmlns:h="http://xmlns.jcp.org/jsf/html"> <h:head> <title>PrimeFaces Test</title> </h:head> <h:body> <p:dataTable id="data-table" var="entry" value="#{dtView.entries}" rowKey="#{entry.id}" selection="#{dtView.selectedEntry}" selectionMode="single"> <p:column headerText="Entry"> <h:outputText value="#{entry}" /> </p:column> </p:dataTable> <h:form id="frmTest"> <div> <p:outputLabel for="@next" value="Selected: "/> <h:outputText id="selected-entry" value="#{dtView.selectedEntry}" /> </div> <div> <p:commandButton value="save input" ajax="false" immediate="true" update="@form :data-table" action="#{dtView.submit()}" /> </div> </h:form> </h:body> </html>
View Layer (Java)
@Data @Named @ViewScoped public class DtView implements Serializable { private List<Product> entries; private Product selectedEntry; @PostConstruct void setup() { entries = List.of( new Product(1, "entry 1"), new Product(2, "entry 2"), new Product(3, "entry 3") ); selectedEntry = entries.get(0); } public String submit() { System.out.println("Selected entry: " + selectedEntry); return null; } }
Console Output Comparison
- PrimeFaces 11.0.0:
Selected entry: null - PrimeFaces 10.0.0:
Selected entry: Product(id=1, name=entry 1)
Workarounds
To avoid the selected field being reset to null, use one of these approaches:
- Move the
<p:dataTable>inside the<h:form>: This ensures it won't be processed during the request values application phase, as it aligns with PrimeFaces' intended usage for selection features. - Use an AJAX-submit button: AJAX requests only process components within the specified
executescope, so the external dataTable won't interfere with the selection value.
Clarification on the Behavior
First, as noted by Jasper, PrimeFaces' SelectionFeature requires <p:dataTable> to be placed inside a form for proper functionality. So your original setup (dataTable outside the form) is technically against the component's designed usage.
To answer your question: Yes, the newer PrimeFaces behavior is more aligned with logical component processing. When you submit a full non-AJAX request, JSF processes all components in the view that have a decode method—even those outside forms. In newer versions, the SelectionFeature's decode logic explicitly sets the selection to null when no row keys are submitted (which happens because the dataTable is outside the form, so its request parameters aren't sent with the form submission).
Your expectation that "values outside the form shouldn't be modified" is understandable, but JSF's component processing model doesn't strictly enforce this for non-AJAX requests. Older versions either skipped setting null (10.0.0 had a check for empty row keys that was removed in 10.0.1) or only set null in limited scenarios (8.x). The updated behavior ensures consistency: if the component can't confirm a valid selection from the request, it resets the bound value.
Underlying Code Change
The behavior shift stems from modifications to the SelectionFeature class:
- PrimeFaces 8: Only called
table.setSelection(null);in specific edge cases. - PrimeFaces 10.0.0: The
decodeSingleSelection()method avoided callingsetSelection()due to a!rowKeys.isEmpty()check, which prevented nulling the value when no row keys were present. - PrimeFaces 10.0.1+ (including 11.0.0): The empty row keys check was removed, so
decodeSingleSelection()now always callssetSelection()—setting the value tonullwhen no valid row keys are submitted from the dataTable.
内容的提问来源于stack exchange,提问作者Jane

