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

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

Related

<p:dataTable filteredValue> is called in spite of rendered=false

I am wondering about the following behaviour of <p:dataTable filteredValue>. Hopefully you can explain it and tell me how to avoid it.
The backing bean method is called even though the corresponding component is not rendered.
<p:panel rendered="#{false}">
<p:dataTable ... filteredValue="#{backingBean.filteredRowModels}">
...
</p:dataTable>
</p:panel>
Do you know how avoid calling the backing bean method if it is not rendered?

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)

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.

Why is this ViewScoped managed bean not working and how can I make it work?

This is the list page I have:
<h:dataTable value="#{actorSearchBacking.all}" var="actor">
<h:column>
<f:facet name="header">
First Name
</f:facet>
#{actor.firstname}
</h:column>
<h:column>
<f:facet name="header">
Last Name
</f:facet>
#{actor.lastname}
</h:column>
<h:column>
<h:form>
<h:commandButton value="Update Actor" action="pocdetail">
<f:setPropertyActionListener target="#{actorFormBacking.stupidActor}" value="#{actor}"/>
</h:commandButton>
</h:form>
</h:column>
</h:dataTable>
which looks something like this in my local environment:
This is pocdetail.xhtml which is the action of Update Actor button:
<h:body>
<h:form id="updateActorForm"
prependId="false">
<h:inputText id="firstname" value="#{actorFormBacking.stupidActor.firstname}"/>
<h:inputText id="lastname" value="#{actorFormBacking.stupidActor.lastname}"/>
<h:commandButton id="updateActorButton"
value="Update Actor!"
action="#{actorFormBacking.updateActor()}"/>
</h:form>
</h:body>
And finally ActorFormBacking is as follows:
#ManagedBean
#ViewScoped
public class ActorFormBacking implements Serializable {
private Actor stupidActor;
public Actor getStupidActor() {
return stupidActor;
}
public void setStupidActor(Actor stupidActor) {
this.stupidActor = stupidActor;
}
}
When I debug the application, I see that setStupidActor is called and property stupidActor is set, but then when getter is called, it is again null.
Since this is a ViewScoped bean, I am expecting the stupidActor not to be null and I expect to see the pocdetail.xhtml page to be filled with values, but all I see is empty input texts since stupidActor is null.
What is it that I am missing? Why is the ViewScoped bean created again and the property is null?
Btw, I am using the annotations from the packages:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
It appears that you're navigating from one view to another view. In other words, you destroy the current view and create a new view. Logically, the view scope will also get destroyed and newly created, including all view scoped managed beans. That the view scoped managed bean happens to be referenced by both views doesn't change this behavior.
A view scoped bean lives as long as the view itself. Like as that a request scoped bean lives as long as the request itself and so on. In order to have a better understanding of the lifetime of various scopes in JSF (and CDI), head to this Q&A: How to choose the right bean scope?
The functional requirement is however understood. You want separate master-detail pages and pass the selected item from the master page to the detail page for editing. There are several ways to achieve this:
The canonical way is to just use a bookmarkable GET link instead of an unbookmarkable POST link. Replace the below piece
<h:form>
<h:commandButton value="Update Actor" action="pocdetail">
<f:setPropertyActionListener target="#{actorFormBacking.stupidActor}" value="#{actor}"/>
</h:commandButton>
</h:form>
by this
<h:link value="Update Actor" outcome="pocdetail">
<f:param name="stupidActor" value="#{actor.id}" />
</h:link>
and in the detail page, obtain the Actor by its identifier which is passed-in as query string parameter. This is fleshed out in detail in this Q&A: Creating master-detail pages for entities, how to link them and which bean scope to choose. A #FacesConverter(forClass) is very useful here.
In case you want to stick to POST for some reason, then your best bet is storing it in the request scope.
FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("stupidActor", stupidActor);
and retrieve it in the #PostConstruct of the very same bean
stupidActor = (Actor) FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("stupidActor");
If you happen to use CDI, or are open to (which I strongly recommend though, JSF managed beans are already deprecated in JSF 2.3.0-m06, see also Backing beans (#ManagedBean) or CDI Beans (#Named)?), then consider using MyFaces CODI's #ViewAccessScoped. Beans with this scope will live as long as all postbacked views explicitly reference the bean. Once you navigate out with a GET, or when the navigated view doesn't anywhere reference that bean, then it will get destroyed.
#Named
#ViewAccessScoped
public class ActorFormBacking implements Serializable {}
Merge the both views into a single view with conditionally rendered master-detail sections. You can find a kickoff example in this Q&A: Recommended JSF 2.0 CRUD frameworks. Or if you happen to use PrimeFaces, How to show details of current row from p:dataTable in a p:dialog and update after save.

Set f:param in external h:commandButton (JSF2)

I really love actionListener and the possibility to pass whole objects as as parameter, instead needing to pass values as String or creating (hidden) form fields. I'm using JSF 2.1 (Mojarra) and RichFaces (for popupPanel).
Currently I'm stuck with the following problem:
I create a table with a button that opens a popup. In that popup, the user can edit the data of the current user/object in the table.
When I click the button in the popup to save the edits, how can I submit the values from the popup AND tell the bean action which userObject I'm edited?
Currently, my workaround is using a hidden inputText field in the popup, but I don't like it this way. Is there an alternative?
This is what I try to achieve (minimized):
<h:datatable value="#{bean.users}" var="user">
<h:column>
Username #{user.name}
</h:column>
<h:column>
<input onclick="showPopup()"/>
</h:column>
</h:datatable>
<rich:popupPanel>
<h:inputText value="#{bean.text}" />
<h:commandButton value="Action" actionListener="#{bean.doSomething}">
<f:attribute name="selected" value="#{userObjectFromDatatable}" /> <-- HOW? -->
</h:commandButton>
</rich:popupPanel>
Looks pretty straightforward for you to preserve the selected the userObject in a conversation-like scope as in #ViewScoped. See this article for details on the #ViewScope. As an example, Declare a variable of the desired type as an instance variable in your backing bean
UserObject userObject;
//getters and setters
In your table you'll now have something like the following to set the selected object in your backing bean
<h:commandButton value="Action" actionListener="#{bean.doSomething}">
<f:setPropertyActionListener value="#{user}" target="#{bean.userObject}"/>
</h:commandButton>
By setting the variable in your backing bean from within the table, the viewscope will ensure that any other operation you perform on that object will be with the same instance, provided you stay on the same JSF view and you do not navigate away from it.

View scoped bean is instantiated twice on one page, if there is no redirect when going to page

I have a page where I use #ViewScoped bean. On page I get data from the bean, and call action on it. Something like this:
<h:form>
<h:dataTable value="#{partyBean.foundOrganisations}" var="party">
<h:column headerClass="header">
<f:facet name="header">
#{msgs['company.registration.number']}
</f:facet>
<h:commandLink value="#{party.registrationNumber}" action="#{partyBean.select}">
<f:setPropertyActionListener value="#{party}" target="#{partyBean.selectedParty}" />
</h:commandLink>
</h:column>
</h:dataTable>
</h:form>
partyBean is #ViewScoped. When I get to this page by navigation rule with <redirect />, everything works fine, but when there is no <redirect />, foundOrganisations are taken from one instance of the bean, but setSelectedParty is called on another instance of the bean when link is clicked. Checked by debug.
Why is that? Can I do something to make it work without <redirect />?
I think its perfectly normal. partyBean is renew with new view.
For a submit to same page you can change your commandLink with command button and return null in action method. In this way JSF acts like same view.
Or you can try keep selectedparty value in a hiddenField (not tested in JSF 2.0)

Resources