I've been using datatables to allow users to enter and edit large amounts of data, but have found that once a large (but uncertain) amount of columns and rows are reached, the form becomes unable to be submitted, and all forms of communication with the server are cut off (unrelated buttons, ajax, etc) until a page refresh is performed.
Is this a limitation of my computer/browser, or is there a hard-coded limit on the maximum quantity of editable data able to be displayed in a datatable? Could this be because of a maximum limit to the number of input fields in a form?
Is the only solution to use paginator for my datatables?
The following is an example that will fail (for me) to be editable if there are too many rows/columns.
<h:form>
<p:dataTable var="_var" value="#{bean.values}" editable="true">
<p:column headerText="Value">
<p:cellEditor>
<f:facet name="output"><h:outputText value="#{_var.value}" /></f:facet>
<f:facet name="input"><p:inputText value="#{_var.value}" /></f:facet>
</p:cellEditor>
</p:column>
<!-- Copy and paste this^ column 15 times -->
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
When using row or cell editor, instruct the cellEdit
event to use partialSubmit="true"
.
<p:dataTable ... editable="true">
<p:ajax event="cellEdit" process="@this" partialSubmit="true" />
...
</p:dataTable>
This will send only the input fields covered by process
attribute (which is either the row or the cell itself) instead of every single input field.
See also:
- How to decrease request payload of p:ajax during e.g. p:dataTable pagination
Okay, I found a solution.
Apparently each input is sent as a GET/POST parameter, and there is a default limit of 512 on servers to prevent DoS attacks.
Unfortunately, Primefaces does not seem to display this error, making it very hard to find.
EDIT: It displays the error, if the logging is set to the correct level. The error is also displayed in the F12 developer tools debugging log.
In short, you must go to your servers standalone.xml
and add:
<property name="org.apache.tomcat.util.http.Parameters.MAX_COUNT" value="10000"/>
Under <system-properties>
EDIT
I refused to give up on a better solution than sending thousands of parameters, and revisited this problem.
It seems that PrimeFaces 5.2 added in the <p:ajax partialSubmitFilter="">
attribute, which allows filtering the inputs that you want. This didn't work for me, as I couldn't narrow down the submitted data to the row using just this.
Instead, I decided to override the PrimeFaces.ajax.Request.send
function, like so:
var pfsend = PrimeFaces.ajax.Request.send;
PrimeFaces.ajax.Request.send = function(cfg) {
if (cfg.event === 'rowEdit' || cfg.event === 'rowEditCancel') {
// This is an operation on a datatable row. Filter for only that row
cfg.partialSubmitFilter = '[data-ri=' + cfg.ext.params[0].value + '] :input';
}
pfsend(cfg); // Run the original function
};
In this way, the value of the first parameter of the cfg (which is the row being edited) is used as the value for finding an element with the attribute data-ri
set to that value (the row).
Note that this does require you to have primefaces 5.2, but for older versions, the same can be achieved by overriding the entire package, and tactically placing similar lines in the right place of the same function (mind that cfg.partialSubmitFilter will not exist).
I found more elegant solution, without overriding function PrimeFaces.ajax.Request.send and still only have it happen on the rowEdit event.
Firstly, define javascript function:
function sendOnlyEditedRow(cfg) {
cfg.partialSubmitFilter = "[data-ri=" + cfg.ext.params[0].value + "] :input";
}
Then call it in onstart callback:
<p:ajax onstart="sendOnlyEditedRow(cfg)" event="rowEdit" listener="#{cc.attrs.detectedFormations.confirmDetectedFormation(i)}"
process="@this detectedFormations" update="detectedFormations"
partialSubmit="true" />