p:dataTable how prevent f:viewParam being invoked on 1st rowEdit then “tick save” using JSF at XHTML level (not in Java in backing bean) - jsf

EDIT: 2017-04-28 The exact same problem (different circumstances/application) is described here: Process f:viewParam only on page load
Primefaces 6.1.RC2
JSF Mojarra 2.3.0
I already have a Java backing-bean based workaround (explained below) for the problem the following behaviour of p:dataTable causes, but I am not very happy with that workaround, and I would like to understand the behavior of p:dataTable row editing better and if possible I would like to find a purely XHTML-level solution to my problem. (BTW I am otherwise very experienced with p:dataTable, which I have used for some very complex applications for some years.)
It is not about an error or bug in p:dataTable, but the way it behaves during row editing causes me a problem in one situation.
The following code examples are completely simplified and adapted for this forum.
I have an entity Element, which has a relationship List<Link> getLinks(), where Link is also an entity.
Element has an editor edit.xhtml.
The aim is to have an composite component links_editor.xhtml that can be embedded in the edit.xhtml.
There is a CDI-compliant #ViewScoped #Named backing bean Manager.
The edit.xhtml relies on an f:viewParam to load an Element for editing:
<f:view>
<f:metadata>
<f:viewParam name="id" value="#{manager.id}"/>
</f:metadata>
</f:view>
Where in the backing bean Manager:
public void setId(Long id) {
if (id != null) {
//load an Element from database for editing by id
And in the links_editor.xhtml:
<cc:implementation>
<div id="#{cc.clientId}">
<p:growl id="testgrowl"/>
<p:dataTable
id="links_table"
editable="true"
var="link"
value="#{cc.attrs.element.links}"
>
<p:ajax
event="rowEdit"
listener="#{cc.attrs.manager.onLinkRowEdit}"
update="#{cc.clientId}:testgrowl"
/>
<p:column headerText="Link title">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.name}" />
</f:facet>
<f:facet name="input">
<p:inputText id="name" value="#{link.name}"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Link URL">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{link.urlAsString}" />
</f:facet>
<f:facet name="input">
<p:inputText id="url" value="#{link.urlAsString}"/>
<p:message
for="url"
display="icon"
/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column>
<p:rowEditor />
</p:column>
</p:dataTable>
The row edit listener:
public void onLinkRowEdit(RowEditEvent event) {
Link link = (Link) event.getObject();
try {
checkLink(link); //throws if URL string malformed
JsfUtil.addInfoMessage("DEBUG: Link: "+link);
} catch (LocalUpdateException ex) {
JsfUtil.addErrorMessage(ex.getMessage());
}
}
(where JsfUtil obviously just leverages FacesContext.getCurrentInstance().addMessage(...))
The issue/concern:
If I edit a Link row in the p:dataTable a first time and then use the "tick save" the onLinkRowEdit listener is invoked, but the diagnostics show that the value appear not to have changed. The reason is that this f:viewParam is invoked:
<f:viewParam name="id" value="#{manager.id}"/>
This (via routes not shown in detail) loads the Element entity again from database via setId(Long id), so that in the composite component edit_links.xthml this essentially resets #{cc.attrs.element.links}, so any changes are discarded.
The interesting thing is that if (without reloading the entire #ViewScoped page) one edits the same p:dataTable row a second time that f:viewParam is NOT invoked, and thereafter it works as desired.
A workaround (rather hacky) is to "block" any attempt to reload the Element by id within the view scope backing bean Manager:
public void setId(Long id) {
//HACK/WORKAROUND: prevent reload of Element by id
if (Objects.equals(id, this.id)) {
return;
}
if (id != null) {
//load an Element from database for editing by id
To be clear, I am aware of the usual strategies for using #PostConstruct and/or lazy database fetching in getters of frequently accessed info under JSF in backing beans. And I don't want to abandon here the f:viewParam approach entirely (and it works well for other situations the same Manager bean is also used for).
My interest is specifically about Primefaces p:dataTable:
Q1: Why does p:dataTable need to call the f:viewParam during the 1st row edit then "tick save", when the row information (in this cases element.links) is clearly already available ?
Q2: Why does p:dataTable NOT need to call the f:viewParam during the 2nd row edit then "tick save" ?
Q3: Is there a JSF XHTML-based way of preventing p:dataTable from calling the f:viewParam at all during a rowEdit then "tick save" (including the 1st go) ?
UPDATE: 2017-04-21: There is now a mini test web app for NetBeans 8.2 demonstrating the problem at:
https://github.com/webelcomau/Webel_PrimeFaces_test_p50445_dataTable_fviewParam
Please just download the master ZIP-archive, unzip it, and open it in NetBeans IDE 8.2. You don't need to Git-clone the project. Make sure you have Glassfish-4.1.1 set as the server for the project.
Both the README there and the web app test page itself give precise steps for reproducing the problem (or the behavior that concerns me).
I have invested some effort in analysing this because I use p:dataTable "embedded" in edit forms together with f:viewParam a lot, and I want to understand this matter better, even if it is not an actual problem with p:dataTable.

Related

Filtering issues (no change in contents) in datatable primefaces 3.5, sorting works

Primefaces 3.5 doesn't seem to filter data at all from the datatable, oddly enough it somehow reorders them as I type, so, there must be some AJAX calls firing, but obviously not the right ones.
<h:panelGroup id="table-wrapper-component">
<prime:dataTable
rendered="#{artifactSelectionBackingBean.visibleComps}"
value="#{artifactSelectionBackingBean.components}"
var="tagInfoObject" emptyMessage="No tags found with given criteria"
filteredValue="#{artifactSelectionBackingBean.filteredComponents}">
<prime:ajax event="filter" global="false" />
<prime:column sortBy="#{tagInfoObject.tagId}"
headerText="Identifier" filterMatchMode="contains" filterBy = "#{tagInfoObject.tagId}">
<h:outputText value="#{tagInfoObject.tagId}" />
</prime:column>
<prime:column sortBy="#{tagInfoObject.type.tagTypeId}"
headerText="Tag Identifier" filterMatchMode="contains" filterBy ="#{tagInfoObject.type.tagTypeId}">
<h:outputText value="#{tagInfoObject.type.tagTypeId}" />
</prime:column>
<prime:column sortBy="#{tagInfoObject.title}" headerText="Title" filterMatchMode="contains" filterBy="#{tagInfoObject.title}">
<h:outputText value="#{tagInfoObject.title}" />
</prime:column>
<prime:column filterBy="#{tagInfoObject.description}"
filterMatchMode="contains" sortBy="#{tagInfoObject.description}"
styleClass="wrap" headerText="Component Description">
<h:outputText value="#{tagInfoObject.description}" />
</prime:column>
</prime:dataTable>
</h:panelGroup>
Any help is appreciated! All the Beans and method calls exist and return the appropriate data, just that the filtering doesn't seem to work at all.
Also, note that sorting functions properly only filtering does not!
The issue was that you always need to wrap any filtering/sorting attributes in a data table with an h:form tag. This is not explicitly specified in the documentation of PrimeFaces, however, it is in the showcase here. I wrapped the whole thing in form tags.
So, don't forget to wrap your data tables in a form if you want any type of interaction provided by primefaces.
Your managed Bean Code will do a lot of good
Post your managed bean code.
May be you have not set the value for artifactSelectionBackingBean.filteredComponents in the managed bean

p:commandButton with p:fileDownload and no ajax only works in second click

I'm using JSF 2.0, Primefaces 3.4.2, Spring 3.1.2.
I'm facing a similar problem of the guy of this link: h:commandButton works from the second click.
Like him I'm not using ajax in the <p:commandButton> but I'm using a <p:fileDownload /> inside the button tag.
I have two views: "list.xhtml" and "downloadView.xhtml". In myBean.java I send a DataModel from view "list.xhtml" to view "downloadView.xhtml" as a request attribute as shown in the code below:
FacesUtil.getServletContext().setAttribute("myDataModelFromRequest", this.myDataModel);
The bean is anotted with #Scope("view")
In view "downloadView.xhtml" I populated succesfully a dataTable with the DataModel sent from request. But the problem happens when I click in the button to download the file. It only works on second try.
I already tried to change the return of my method from null to "downloadView" but the problem was not solved.
In debug mode I noticed that only enter in the "downloadMethod()" on second click.
Anyone have an idea to solve it?
myBean.java
public String viewListMethod() {
//some work here...
FacesUtil.getServletContext().setAttribute("myDataModelFromRequest", this.myDataModel);
return "downloadView";
}
downloadView.xhtml
<h:form id="formId" prependId="false">
<p:dataTable
id="dataTableId" var="myVar" value="#{myDataModelFromRequest}"
selection="#{cargaProcessoControlador.myArray}"
paginator="true" rows="10" paginatorPosition="bottom" paginatorAlwaysVisible="false">
<f:facet name="header">
bla bla bla
</f:facet>
<p:column selectionMode="multiple" style="width:18px" />
//collumns here...
</p:dataTable>
<p:commandButton id="btDownload" ajax="false" value="Download" icon="ui-icon-document" >
<p:fileDownload value="#{myBean.downloadMethod()}" />
</p:commandButton>
</h:form>
The scope "view" on spring doesn´t exist... So you created your own, right? Just to check...
I had that kind of problem once, and I think it was something to do with validation... the
immediate=true attribute solved my problem.
This is something to do with the scope of the page. Your problem is due to partial rendering of page. Initially when you load the page it is not getting loaded fully and because of that the button is not part of that particular view when you try to click on the button for the first time. Try to make you view proper or explicitly render the page from the backing bean before displaying the page

<h:commandLink> not working inside a <h:dataTable>

I will try to explain myself:
I'm working on a JSF project using java, JSF 2.0 and RichFaces 4.2.1.
When I access my jsf it just loads a search filter and a commandLink. The commandLink will launch a method in my backingBean to load data that it will be displayed in a dataTable.
<h:commandLink id="btnRecords">
<f:ajax render="myCompAjax" event="click" listener="#{myBean.loadRecords}" />
<h:graphicImage value="img/ico_new.gif" alt="#{bundle['button.search']}" />
</h:commandLink>
The datatable is not visible at first, but once you click on the commandLink a flag in the backingBean will change and the table displays with data I just loaded.
<a4j:outputPanel ajaxRendered="true" id="myCompAjax">
<h:dataTable id="recordsTable" value="#{myBean.records}"
var="item" rendered="#{myBean.flagShowTable}">
<h:column headerClass="thPijama" >
<f:facet name="header">
<table><tr class="thPijama"><td></td></tr></table>
</f:facet>
<h:commandLink action="#{myBean.goNextPage}">
<h:outputText value="Go Next Page" />
<h:inputHidden value="#{item}" />
</h:commandLink>
</h:column>
</h:dataTable>
</a4j:outputPanel>
Problem is the commandLink action inside of the dataTable isn't working at all. I just want to navigate to another jsf. In fact, what it does is hiding the dataTable and leaving the filter unchanged. The action method remains unreachable.
Of course, it works if I set the same commandLink outside the dataTable.
I cannot use Session Scope Beans because the people I work for don't approve it.
Can anyone help me?
Thanks for the hint.
I cannot use Session Scope Beans because the people I work for don't approve it.
Are you implying that placing the bean in the session scope instead of the request scope actually solved the problem? If so, then just put the bean in the view scope.
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
// ...
}
This way the bean will live as long as you're interacting with the same view by ajax requests. The bean is not been shared in other browser tabs/windows in the same session (which is among the architects indeed the major reason to forbid its use in case of simple views).
See also:
How to choose the right bean scope?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 4 applies to you

JSF 2.2 #ViewScoped binding bug?

I've read about the binding bug with #ViewScoped (BUG REPORT) and that it was fixed in one of the latest versions of JSF, so I tested this with the 3 latest versions of JSF and tried using the
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
fix to solve it, but no luck.
I have a primefaces datatable where I have filters in each column header.
<p:column id="cpfHeader" sortBy="#{cliente.nrCpf}"
filterMatchMode="contains">
<f:facet name="header">
<h:panelGrid columns="1">
<h:outputText value="CPF" />
<p:inputText value="#{cadastroClienteBean.cliente.nrCpf}">
</p:inputText>
<p:commandButton
actionListener="#{cadastroClienteBean.getClientesBusca}"
update="#{form}:tabelaCliente:tblCliente" value="Filtrar"></p:commandButton>
</h:panelGrid>
</f:facet>
#{cliente.nrCpf}
</p:column>
Before I changed the JSF version, everytime I'd click on the "Filtrar" button, a new instance of my cadastroClienteBean would be created. Now that I've changed it, it seems that the ManagedBean is not being instantiated everytime, but the cliente variable is becoming null, eventhough I instantiate it on the constructor.
public CadastroClienteBean(){
cliente = new Cliente();
init();
}
EDIT: After debugging a bit I found out that the value of the filter is being set on the variable and right after that the setCliente() is being called and setting it to null, but I don't know why.
Figured out what was happening the selection="#{cadastroClienteBean.cliente}" attribute on the dataTable was setting the client to null since there was no line selected.

input binding in ui:repeat in jsf

i am using facelets jsf 2.0 with primefaces 3.0.M2 component library.
i am trying to achieve dynamic numbers of rows including iput fields that are filled when a datatable selection occurs.
whenever a selection is made the dynamic rows generated correctly with input fields but after the first selection for following selections dynamic row count changes correctly but the input fields does not update and keeps showing inputs from the first selection.
here is how i iterate list in facelet;
<ui:repeat value="#{goalEntranceBean.selectedCard.parameterList}" var="prmBean" >
<li><h:outputText value="#{prmBean.lookUp.value}"/></li>
<li>
<h:outputText value="Weight:"/>
<p:inputText id="wx" required="true" value="#{prmBean.weight}">
</p:inputText>
<h:outputText value="Percent:"/>
<p:inputText required="true" value="#{prmBean.percent}">
</p:inputText>
</li>
</ui:repeat>
my bean where i get the list of cards and set the selectedCard with rowSelect event in datatable.
#ManagedBean(name = "goalEntranceBean")
#ViewScoped
public class GoalEntranceAction implements Serializable {
private List<ScoreCard> personalCards = new ArrayList<ScoreCard>();
private ScoreCard selectedCard = new ScoreCard();
......
}
when i checked in debug mode i can see the true list but in screen the elements does not change.
This is a common problem (gets asked every couple of days). To make long story short, inputs inside ui:repeat do not work, period.
It is a problem with JSF, a long standing, famous one. Maybe it will be fixed. Maybe not, it seems that no one really cares (I mean - an input? in a... ui:repeat? such crazy scenario!).
A quick-fix is to use a h:dataTable, possibly ungodly abused with css to make it look like a list. A long-fix is to use some iterator from a different library. Primefaces has an element that should work that renders an unordered list.
thanks for your replies. Sorry for forget sharing the solution.
As i mentioned above i have primefaces datatable.
On row selection event i render datatable and want to update the cells of that datatable.
USING p:inputtext easily solved my problem. Now i can change the data on screen and i can see the values after update operation on screen. I don't understand the reason but it works.
<p:dataTable var="orgPrmBean"
value="#{scoreCardOperationsBean.selectedCard.orgParameterList}"
emptyMessage="#{labels.norecord}"
rowKey="#{orgPrmBean.id}"
>
<p:columnGroup type="header">
<p:row>
<p:column headerText="Parameters" colspan="3" style="text-align:left;width:480;"/>
</p:row>
</p:columnGroup>
<p:column style="text-align:left;width:200px;">
<h:outputText value="#{orgPrmBean.info}"/>
</p:column>
<p:column style="text-align:left;width:180px;">
<p:inputText value="#{orgPrmBean.weight}"
rendered="#{scoreCardOperationsBean.selectedCard.goalEdit}">
<f:convertNumber maxFractionDigits="0"/>
</p:inputText>
</p:column>
</p:dataTable>
It IS possible to make it work, but the solution is to bind the inputs to a backing bean, and update the values of the controls in the backing bean via listeners (using the new value received in the argument). Obviously this isn't a good solution if you have a complex form, as you need to add a listener/control in the backing bean for each control in the page, but it's practical if you just have one or two inputs.

Resources