This question already has an answer here:
How to decrease request payload of p:ajax during e.g. p:dataTable pagination
(1 answer)
Closed 7 years ago.
I have a datatable in which each row has 24 hour input fields in it. At one point of time there are more than 1000 editable input fields. I noticed that while using p:cellEditor during ajax calls primefaces is submitting the entire datatable. How can I avoid that?
Please find below the code that I have, and also find the comments on each important parts in them.
<!-- Fires the cellEdit event to trigger the validations to happen as user tabs out of the input box -->
<p:ajax event="cellEdit" listener="#{renderValidator.onCellEdit}" update=":#{p:component('globalMessages')}" process="#this" />
<p:column id="hour1" styleClass="col-right col-90">
<f:facet name="header">
<h:outputText value="1" escape="false"/>
</f:facet>
<p:cellEditor >
<f:facet name="output">
<h:outputText value="#{row.amount[0]}" escape="false">
<f:convertNumber maxFractionDigits="3" minFractionDigits="3" maxIntegerDigits="5" />
</h:outputText>
</f:facet>
<f:facet name="input">
<p:inputText id="hour1Input" value="#{row.amount[0]}" maxlength="10" size="10" readonly="#{row.readOnly}" onchange='PowerMeter.setPowerMeterChange()'
styleClass="col-right" valueChangeListener="#{row.setDirtyFlag(true)}" >
<!-- formats data the way its displayed -->
<f:convertNumber maxFractionDigits="3" minFractionDigits="3" maxIntegerDigits="5" />
<!-- validates the input value w.r.t a custom validator -->
<f:validator validatorId="hourlyValueValidator" for="hour1Input" />
<!-- javascript restricting user to input alpha numeric characters -->
<pe:keyFilter testFunction="return PowerMeter.isValidMWH(this, c);" />
</p:inputText>
</f:facet>
</p:cellEditor>
</p:column>
On Ajax requests, JSF sends the data for all input components in the form by default. Even if only one out of 100 components is executed in the partial lifecycle. With PrimeFaces you can alter this behavior by setting partialSubmit to true like this:
<p:ajax partialSubmit="true" event="cellEdit" process="#this"
listener="#{renderValidator.onCellEdit}"
update=":#{p:component('globalMessages')}"/>
Primefaces uses the PrimeFaces.ajax.AjaxUtils.send function to build Ajax requests. To determine what data need to be send to the server it uses jQuery find function and then serializeArray which is used to build a POST requests.
componentPostParams = jqProcess.find(':input').serializeArray();
Unfortunately when the liveScroll attribute is enabled for the <p:DataTable> and there is already a huge amount of data fetched it will process all input controls no matter if <p:cellEditor> have only one input facet visible.
To change this functionality I overrode PrimeFaces.ajax.AjaxUtils.send function in the below form
var pFacesSend = PrimeFaces.ajax.AjaxUtils.send;
PrimeFaces.ajax.AjaxUtils.send = function(cfg) {
if (myCase) {
// Custom send
} else {
pFacesSend(cfg);
}
};
And in myCase I changed additionally serialization from this:
componentPostParams = jqProcess.find(':input').serializeArray();
Into this:
if (!customSerializationCondition) {
componentPostParams = jqProcess.find(':input').serializeArray();
} else {
componentPostParams = jqProcess.find(':input').filter(function() {
return $(this).parent().css('display') !== 'none';
}).serializeArray();
}
This solution builds a POST request that only includes visible input fields and because of my editMode set to cell I have only one <input> visible.
It works for Primefaces v4.0 and should work whenever the input parent tag uses css display attribute to hide input facet in the editor.
Related
Prerequisites:
JSF 2.1
Primefaces 5.2
Glassfish 3.1
Story:
I got a datatable displaying some editable values.
The amount of columns is dynamic.
In the same form is a button calling a save-action of my bean to save all edited data.
The function it self is working perfectly fine
Implementation:
<p:dataTable id="dataTable" scrollable="true"
widgetVar="wigVardataTable"
value="#{myBean.dataList}"
var="data"
editable="true"
editMode="cell"
rowKey="rowkey">
<p:columns var="col"
value="#{myModel.columnList}"
style="font-size: 12px">
<f:facet name="header">
<h:outputText
value="#{col.header}" />
</f:facet>
<p:cellEditor>
<f:facet name="output">
<h:outputText
value="#{myModel.getValueForTableCell(data, col).value}" />
</f:facet>
<f:facet name="input">
<p:inputText
id="inputTxt"
value="#{myModel.getValueForTableCell(data, col).value}"
style="width:100%">
</p:inputText>
</f:facet>
</p:cellEditor>
</p:columns>
</p:dataTable>
Problem:
When pressing the save button while a table cell is being edited and didn't loose its focus yet, the new value inside the inputtext of the tablecell won't be written back into my bean and due to that won't be saved.
Question:
How can i write back the data into my backing bean, before the button action is executed?
This behavior is caused by wrong ordering of ajax events. When the command button is invoked while having a cell editor open, then the ajax event of the command button is fired before the ajax event of the cell edit.
We'd thus like to swap around them. Without editing the PrimeFaces source code, you could achieve this by explicitly invoking saveCell() function of the <p:dataTable> widget when there's a cell editor open.
So, given a
<h:form>
<p:dataTable ... widgetVar="wigVardataTable" />
<p:commandButton ... />
</h:form>
you can achieve the desired behavior by adding the below onclick to the <p:commandButton>:
onclick="var d=PF('wigVardataTable'), c=d.jq.find('td:has(.ui-cell-editor-input:visible)'); if(c.length)d.saveCell(c)"
Basically, it first finds the cell with an open cell editor and then invokes saveCell() on it.
Another, less elegant, way is explicitly invoking showCellEditor() function of the <p:dataTable> widget without passing the expected target cell in a try-catch block where the exception is ignored.
onclick="try{PF('wigVardataTable').showCellEditor()}catch(ignore){}"
It will save any opened cell first and later throw an error that no new target cell was specified as argument, but that could be ignored as shown above.
Noted should be that this all works regardless of whether you use <p:columns> or <p:column>, and also regardless of whether you use a normal model or an overcomplicated model ;) This trick is tested on both your PrimeFaces 5.2 version and the current PrimeFaces 6.0 version.
Here is a generic solution inspired by BalusC answer if you have other datatables with cell editMode :
<script type="application/javascript">
function saveAllCellsBeforeSubmit() {
for (var widgetName in PrimeFaces.widgets) {
if (PrimeFaces.widgets[widgetName].hasOwnProperty('cfg') && PrimeFaces.widgets[widgetName].cfg.hasOwnProperty('editMode') && PrimeFaces.widgets[widgetName].cfg.editMode === 'cell') {
var d = PF(widgetName);
var c = d.jq.find('td:has(.ui-cell-editor-input:visible)');
if (c.length) {
d.saveCell(c);
}
}
}
}
</script>
I am new two JSF and Prime-faces. I suppose to finish the task and i almost completed but have to fix final requirement.
Here is the requirement:
The main objective of the task is to display the enable/disable check boxes associated with database values.
I have to do sorting and filtering values too.
Here is the picture what i have tried.
I can able to display the Boolean value or just empty check box or enable check-box.
[![In screenshot you can see that cmistes column displays all check-boxes in disabled mode and other two columns displays enabled but disabled as i wrote different code to check.][1]][1]
Here is the code to display:
The below code display only disabled checkboxes..
<p:column sortBy="#{dossier.cmistes}" width="85" filterBy="#{dossier.cmistes}" filterStyle="width:50px; font-size:10px;">
<f:facet name="header">Cmistes</f:facet>
<h:selectBooleanCheckbox id="cmistes" disabled="#{dossierBean.dossier.cmistes}" styleClass="benefSelection" />
</p:column>
And this code displays enabled check-box but not disabled..
<p:column sortBy="#{dossier.vbtaz}" width="85" filterBy="#{dossier.vbtaz}" filterStyle="width:50px; font-size:10px;">
<f:facet name="header">vbtaz</f:facet>
<h:selectBooleanCheckbox id="vbtaz" checked = "true" rendered="#{dossier.vbtaz}" styleClass="benefSelection" />
</p:column>
Generated getters and setters are:
private Boolean cmistes; //IND_CMISTES NUMBER(1,0)
public Boolean getCmistes() {
return cmistes;
}
public void setCmistes(Boolean cmistes) {
this.cmistes = cmistes;
}
Any suggestion ?
Thanks.
If I understand your question correctly, you want to show ALL checkboxes, but you want them to be enabled or disabled depending on your database data.
First, you are currently using the rendered attribute which tells the server to generate or not the HTML code. You want to use the disabled attribute like this :
<h:selectBooleanCheckbox id="cmistes" disabled="#{dossierBean.dossier.cmistes}" styleClass="benefSelection" />
Also note the == '1' is removed, because your method is already returning a Boolean, and don't expect the right result by comparing a Boolean with a String.
More info :
h:selectBooleanCheckbox
Finally,here is the solution for the above question which i only asked.
I used disabled attribute to display rendered /disabled check-boxes.
<p:column sortBy="#{dossier.cmistes}" width="85" filterBy="#{dossier.cmistes}" filterStyle="width:50px; font-size:10px;">
<f:facet name="header">Cmistes</f:facet>
<h:selectBooleanCheckbox id="cmistes" disabled="true" value="#{dossier.cmistes}" styleClass="benefSelection" />
</p:column>
<p:column sortBy="#{dossier.vbtaz}" width="85" filterBy="#{dossier.vbtaz}" filterStyle="width:50px; font-size:10px;">
<f:facet name="header">vbtaz</f:facet>
<h:selectBooleanCheckbox id="vbtaz" disabled="true" value="#{dossier.vbtaz}" styleClass="benefSelection" />
</p:column>
But, If i want to display check-boxes with tick symbol instead of gray color..
Any sugestion?
I've added OmniFaces to my Primefaces application primarily for being able to update a single row of a dataTable. I'm calling Ajax.updateColumn(dataTable, 1) on push event, but nothing gets updated. Eg. one of my cells is like this
<p:column style="width:40px;text-align: center;"
toggleable="false" styleClass="smallPadding unmarkable">
<f:facet name="header">
<p:commandLink styleClass="ui-icon ui-icon-car"
style="display: inline-flex;" id="carIcon" />
</f:facet>
<p:tooltip for="carIcon" value="Anzahl freie Fahrzeuge" />
<h:outputText
value="#{editLoad.getAmountOfUnusedOrderPositions(order)}" />
<h:outputText value="/#{order.orderPositions.size()}" />
</p:column>
I've debugged and #{editLoad.getAmountOfUnusedOrderPositions(order))} returns 0, but the wrong value (8) is displayed after the update.
From the Ajax#updateColumn() javadoc:
public static void updateColumn(UIData table, int index)
...
Note that the to-be-updated direct child of UIColumn must be a fullworthy JSF UI component which renders a concrete HTML element to the output, so that JS/ajax can update it. So if you have due to design restrictions for example a <h:panelGroup rendered="..."> without an ID, then you should give it an ID. This way it will render a <span id="..."> which is updateable by JS/ajax.
Your <h:outputText> of interest doesn't have a id. Give it one.
<h:outputText id="amountOfUnusedOrderPositions"
value="#{editLoad.getAmountOfUnusedOrderPositions(order)}" />
This question already has an answer here:
Conditionally make inputs required depending on checkbox value
(1 answer)
Closed 8 years ago.
I am using JSF 2.2 with Primefaces 4 on a Tomcat 7.
I have a form in which certains fields are required depending on the value of a checkbox. So In the example below, the fields in the fieldset are required only if the checkbox is checked (which is, by default) :
<h:form id="formId">
...
<p:selectBooleanCheckbox id="fieldId1" value="#{myBean.firm}">
<p:ajax event="change" process="#this :formId:fieldsetId" update="#this :formId:fieldsetId"/>
</p:selectBooleanCheckbox>
...
<p:fieldset id="fieldsetId">
<p:inputText id="field2" value="#{myBean.field2Value}" required="#{myBean.firm}"/>
<p:inputText id="field3" value="#{myBean.field3Value}" required="#{myBean.firm}"/>
</p:fieldset>
</h:form>
My problem is that the ajax request passes through the validation, so when i unchecked the checkbox, the validation fails on the inputFields if they are not filled, and the model is not updated.
So my attribute firm is still set to true in myBean and my inputText fields are still required.
At first I forgot to process the fieldset
<p:ajax event="change" process="#this" update="#this :formId:fieldsetId"/>
This worked, or I though, but as the field are not processed, if I filled some fields before unchecking the box, all the data were lost. Setting immediate="true" won't work either in that case.
It seems to me to be a very simple and common usecase, and I can't believe there is not a solution.
Thanks
Hy,
<h:form id="formId">
...
<p:selectBooleanCheckbox id="fieldId1" value="#{myBean.firm}">
<f:ajax listener="#{bean.checkBoxListener}" immediate="true" update=":formId:fieldsetId" />
</p:selectBooleanCheckbox>
...
<p:fieldset id="fieldsetId">
<p:inputText id="field2" value="#{myBean.field2Value}" required="#{myBean.firm}"/>
<p:inputText id="field3" value="#{myBean.field3Value}" required="#{myBean.firm}"/>
</p:fieldset>
</h:form>
in the bean
public void checkBoxListener(ValueChangeEvent event) {
this.firm = (Boolean) ((UIInput) event.getComponent()).getValue();
}
I have a JSF datatable with a bunch of rows, with each row having a selectOneMenu inside of it like this:
<h:form
<h:dataTable id="myTable"
binding="#{myBean.dataTable}"
value="#{myBean.dataTableRows}" var="row"
first="0" rows="0" dir="LTR" frame="hsides" rules="all">
<h:column>
<f:facet name="header">
<h:outputText value="Sample Name" />
</f:facet>
<h:outputText value="#{row.sampleName}" />
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Role" />
</f:facet>
<h:selectOneMenu value="#{row.role}"
id="roleInput">
<f:selectItems value="#{myBean.allRoles}" />
</h:selectOneMenu>
</h:column>
</h:dataTable>
<h:commandButton value="Save" action="#{myBean.save}" />
</h:form>
However, I can't seem to figure out how get the selected role out of each row in the save method. In other words, I want to save each row's value. I saw this article, which explains how to save an input text box:
http://balusc.blogspot.com/2006/06/using-datatables.html#EditableDatatable
but it doesn't seem to apply to the h:selectOneMenu case. Does anyone have any example code that does this?
Thanks!
I see your table has binding to your bean. In your bean you can use the getDataTable() method and access it. Java doc says:
public Object getRowData()
Return the data object representing the data for the currently selected row index, if any.
So if you do your code like:
List<String> selectedRowData = (List<String>) getDataTable().getRowData()
You can then access all the fields the user has chosen. Im using this in my own project and its working. The only difference is that Im casting to my own type instead of List<String>
There are no obvious errors in the form - if your save method is not being invoked, try adding a messages tag to your form to help track down the source of the problem. It would help if you posted a sample bean that reproduces the problem and state the JSF implementation and version you are using.