Action-listener on Rowtoggle-ajax event in datatable gets incorrect parameter-value - jsf

I have a datatable with a rowtoggler:
<p:dataTable expandedRow="#{line.toggled}"
value="#{cartController.getLines(agreement.id)}"
var="line" widgetVar="table" rowIndexVar="rowIndex">
<p:ajax event="rowToggle"
listener="#{cartController.toggleAndSaveLine(line)}"
disabled="#{facesContext.validationFailed}"/>
...
</p:dataTable>
My goal is to keep track of which row that is toggled on the server side, so I call toggleAndSaveLine in my cartController on rowToggle. My problem is that no matter which one of the rows I toggle, the line-parameter in toggleAndSaveLine-method will always be the last element in the provided list of values, making it impossible to keep track of which row that was toggled. The strange thing is that I use the var line in other similar AJAX-calls and there it works perfectly.
Any ideas what might be wrong? I'm using PF6.

Related

How to build a dynamic grid and only show three columns in a row (JSF 2.2 and BootsFaces)

I am trying to layout a page with Bootsfaces and JSF 2.2. I like to show only three column in a row and then start new row but don't know, how to implement this.
<h:form>
<b:container>
<b:row>
<ui:repeat value="#{ClientBean4.custs}" var="custs">
<b:column col-md="4"><h:outputText id="output" value="#{ClientBean4.counter}" /> </b:column>
<h:panelGroup rendered="#{ClientBean4.counter == 0}">
</b:row><b:row>
</h:panelGroup>
</ui:repeat>
</b:row>
</b:container>
</h:form>
after a long time, I wrote above code, but it's givng error like 'h:panelgroup' should be properly closed. It's giving meaning, that I started panelGroup and then closing a row, starting a new row, and then close panelGroup.
So, Is anyone have idea, how to implement a layout, where a row will have three columns (showing customer's object details per column), then close the row and start a new row. obvisouly, I dont know, how many objects will be in the list.
BootFaces offers a component that handles this. More specifically you can use <b:panelGrid columns="3"> to achieve this. This will give you a dynamic grid system that will grow vertically as you populate it but retain the number of rows that you specify.
You can see the component in action here, https://showcase.bootsfaces.net/layout/panelgrids.jsf
PrimeFaces also has a component for this, but I assume you want to use BootFaces as your original code uses it. If you prefer PrimeFaces, you can use the <p:dataGrid> component, which does something similar. This component even handles pagination.

Too much data in p:dataTable results in broken row/cell edit submits

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" />

How to change order in which the components are processed

I have a selectOneMenu and an editor. What I want is to submit the value of the editor before the value of the selectOneMenu. The code looks like this
<p:selectOneMenu value="#{myBB.selectedItem}">
<f:selectItems value="#{myBB.selectItems}"/>
<p:ajax event="change" process="itemText #this" update=":mainForm"/>
</p:selectOneMenu>
<p:editor id="itemText" value="#{myBB.selectedItem.text}"/>
It looks like the order of elements in process="itemText #this" doesn't matter, because when I change it, the values are submitted in unchanged order.
The problem is, that the selectedItem of the editor is changed by the selection before the value from the editor is submitted.
Am I right, that the order doesn't matter and it is submitted based on the order in the DOM tree? (When I change order of the input fields it's working as I would like to)
What is the best way to work around this?
You shouldn't rely on things like layout or processing order in your code. If the problem is that itemText value is reset when selectedItem is changed, then bind the text to separate String text bean variable, and update selectedItem.text in some other code, maybe <p:ajax listener="#{...}".

Delete entity of repeat in form and visualize result with update does not work

I have an List of Items, where I want to be able to add and remove items. For that, I add the whole List in a and everytime add or remove an item, I call update from primefaces. The code looks like this:
<h:panelGroup id="group">
<ui:repeat value="#{manager.values}" var="item">
<p:inputText value="#{item.name}"/>
<p:commandButton value="Remove" action="#{manager.remove(item)}" onsuccess="update_values();"/>
</ui:repeat>
</h:panelGroup>
<p:remoteCommand update="group" name="update_values"/>
<p:commandButton value="Add" action="#{manager.newValue()}" update="group"/>
Adding works fine, but everytime I call remove, the behaviour is strange. The item, which is the most right is deleted, and the name of the others remain unchanged, even if I remove the most left item.
After some debugging, I found out that this is because of the value="#{item.name}": The item is deleted correctly, but after the deletion, the value of the fields that exist are set for the values the fields had before. So all in all, the most right field does not exist anymore, because ui:repeat has one item less, but the others get the values they had before, so it is only possible to remove the most right field.
Has anybody an hint how to solve this? One solution maybe would be to clear every field with javascript, but I'd rather like the frameworks to solve the problem than to code something myself.
Try it like so:
<p:commandButton value="Remove" action="#{manager.remove(item)}" update=":directPath:group" process="#this" />
maybe the fact that there is no hard update on the button itself might be the cause.
PS
Is there an <h:form> around your element?

JSF - How to reset the <ice:dataTable> value list

Couple of days ago I started JSF with Iceface. I have a dataTable and when I delete a row,
It deletes the particular list entry from the back-end. Also dataTable remove a row, but not the one I deleted.
(It is not about the complete row. Its only a column.)
I'm using a suggestion box for each row. Problem only happens with that suggestion box field. But without that suggestion box, it works fine.
I thought if I could refresh/sync again the dataTable with it's bean property, just before rendering it, might solve the problem.
(From back-end it maintains the exact data set that I want to populate in my dataTable.)
At the moment what I want to know is, how can we re-sync the dataTable with it's new value, before render the response.
If you have any other idea please share it with me.
Thanks!
I have done a mistake :(
I haven't add the value="#{o.itemId}" property.
This is my suggestion box.
Thanks!
<ice:selectInputText id="sugestBox" rows="10" width="290"
listVar="item"
valueChangeListener="#{o.itemAutoCompleteBean.updateList}"
actionListener="#{o.lst}"
listValue="#{o.itemAutoCompleteBean.matchesList}"
value="#{o.itemId}">
<f:facet name="selectInputText">
<ice:panelGrid columns="3" style="margin-bottom:20px; "
columnClasses="sgstItemDropCol,sgstItemDescCol,sgstItemCatCol" >
<ice:outputText value="#{item.itemId}"/>
<ice:outputText value="#{item.description}"/>
<ice:outputText value="#{item.category}"/>
</ice:panelGrid>
</f:facet>

Resources