This question already has an answer here:
How to call JSF backing bean method only when onclick/oncomplete/on... event occurs and not on page load
(1 answer)
Closed 6 years ago.
Recently I ran into a problem with one of my . I have a separate xhtml containing conditionally rendered icons/links to show different kinds of popups. This xhtml is basically a container for specific kinds of popups that I can include on different pages. The rendered conditions (and a passed ui:parameter) make sure only the relevant icons/links get shown depending on where this xhtml is included. This prevents me of having to write lots of different ui:includes on each page.
For some popups it's necessary to prepare some data, which is done via the onclick attribute of an a4j:commandLink. Then, the oncomplete will show the actual popup like so:
<a4j:commandLink render="clientGroupMemberInfoPopup" rendered="#{assignmentDO.clientGroupMember}"
onclick="#{clientInfoBean.registerGmClientGroupMember(assignmentDO.gmClientGroupMemberDO)}"
oncomplete="RichFaces.ui.PopupPanel.showPopupPanel('ClientInfo')">
<h:graphicImage value="/img/icons/icon_info_sm.png" rendered="#{!printFriendly}"/>
</a4j:commandLink>
The corresponding bean:
#ManagedBean
#ViewScoped
public class ClientInfoBean {
#EJB
private ClientService clientService;
#Getter
#Setter
private ClientContextDO clientContextDO;
#Getter
#Setter
private GmClientGroupMemberDO gmClientGroupMemberDO;
#Getter
#Setter
private Long clientId;
public void registerGmClientGroupMember(final GmClientGroupMemberDO aGroupMember) {
gmClientGroupMemberDO = aGroupMember;
clientContextDO = clientService.findByClientId(gmClientGroupMemberDO.getClientId());
}
}
In this case above the rendered condition of the a4j:commandLink evaluates to true. However... the onclick is evaluated every single time, on every page this xhtml is included, once the rendered condition evaluates to true. Even when the page is still loading and nobody has clicked on anything yet!
Why? And what's the best way to prevent this? There's some relatively heavy db-stuff being done to prepare all the info necessary for the popup. I only want this stuff done the moment someone actually clicks on the link for the popup, not during page rendering phases.
There IS a duplicate of this question, I'm sure but I cannot find it. I'll remove this answer when BalusC flags it as such.
The onclick is for executing javascript, not accessing a server-side method. So the EL in it is evaluated as a value expression, not a method expression. So the output is considered as javascript. Consequently it is just evaluated at render time and re-evaluated when clicked.
The solution is to change the onclick to action
<a4j:commandLink render="clientGroupMemberInfoPopup" rendered="#{assignmentDO.clientGroupMember}"
action="#{clientInfoBean.registerGmClientGroupMember(assignmentDO.gmClientGroupMemberDO)}"
oncomplete="RichFaces.ui.PopupPanel.showPopupPanel('ClientInfo')">
<h:graphicImage value="/img/icons/icon_info_sm.png" rendered="#{!printFriendly}"/>
</a4j:commandLink>
I am building a JSF 2.0 Application using primfaces. I have a managed bean that has several objects for different scenarios.
In this particular portion of the application I move from a data table/form to a managed bean with an identification number.
I pull the information from the database and even have it in the log. However when I make it to the
JSF xhtml page the object values are null and I can't seem to figure out why, any help would be great as I am getting no errors,
exceptions, or warnings in the logs and all information seems to point to the loading of the data including the log.
JSF Page that I am coming from... jobs.xhtml (I am using jsf 2.2 and primefaces to build this application) From this page the
link specifies a job number to be retrieved and the next bean will retrieve that job based on the job number I have it down to just a button
that will take you to the primary method and get the information to the next page...
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<body>
<div style="margin-bottom:350px;">
<p:column>
<h:form>
<h:commandButton id="editProject" action="#{editProjects.getProjectForm()}" value="Edit" />
</h:form>
</p:column>
</div>
</body>
</html>
EditProjects.java the backing bean for the editMailerJob.xhtml which will take in the medium id and the job number the medium id will be used
to direct the application to the next page and the job number will be used to retrieve a specific job
::::UPDATED::::
package beans;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.RossProjectManagement.rpm.objects.MailerProject;
#ManagedBean
#RequestScoped
public class EditProjects implements Serializable {
/**
*
*/
private static final long serialVersionUID = -6680733133634363295L;
private final Log LOG = LogFactory.getLog(this.getClass().getName());
// Editable projects
private MailerProject edit_mailer = new MailerProject();
//Changed this to be a static set value
private String mailerProject = "THIS IS THE MAILER STRING";
public int getProjectForm() {
loadEditMailer();
return 1;
}
public void loadEditMailer() {
this.edit_mailer = new MailerProject("REDJ15061005",
convertDate("2015-06-29"), false, "RickD",
"RickD and the Gang", "new", true, true, "SPEC", 1, 1, 1,
"REDJ15061005", "11X17", "SPOT_COLOR", "20,000",
convertDate("2015-06-30"), convertDate("2015-07-13"),
convertDate("2015-07-06"), convertDate("2015-07-06"),
convertDate("2015-07-15"), true, "BDC",
"someone#example.com", "STANDARD", 7500.00, "CONQUEST",
"NONE", "JS DIRECT", "NONE");
//Commented this out to keep the value static
//setMailerProject(edit_mailer.toString());
LOG.debug(":::MAILER PROJECT TO STRING::: " + this.mailerProject);
}
public Date convertDate(String date) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = null;
try {
date1 = df.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return date1;
}
}
JSF page that I am redirecting to editMailerJob.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<body>
<div style="margin-bottom: 350px;">
<h:outputLabel>#{editProjects.edit_mailer}</h:outputLabel>
<h:outputLabel>Mailer String::: #{editProjects.mailerProject} </h:outputLabel>
</div>
</body>
</html>
The log shows that all of the information has been received and loaded but shows no where that the information has been cleaned or the object made anew. I have tried instantiating the object in different places at different times but that didn't work.
Before I leave the bean the object has value, when I get to the page the object has no value, I don't understand why
I then tried loading the information from different places. I have tried changing the scope of the bean from request to view back to request but no luck, (I thought about doing session but I didn't see the benefit as well as I just couldn't see reasoning to put all of that information into the session).
The problem seems to be revolving directly around the bean itself and the getProjectForm Method because at one point the object is loaded and then it just loses all of its information.
All of my values seem to be correct as far as I can tell but none of the information is loading.
I can't seem to wrap my head around the issue so any help would be greatly appreciated. if any more information is needed just let me know.
I hope all of this helps Let me know if I have forgotten anything.
EDITS:::
I have created just a string to see if at any point it would be delivered either, and so far I am still getting nothing, the .xhtml page is reading that it exists but not that it has value. Still working with this if anyone else has a solution it would be awesome, or if you know the solution and could at the least point me in the right direction that would be great also.
UPDATE #2
So I found that if I set the value outside a method it will properly be displayed so it seems to me like the methods are keeping the value from the xhtml page. What is the deal with that, I have getters and setters for the variables I have them declared and defined properly, but for what ever reason the values when loaded by the method are not kept outside the method, the values are not able to be accessed by the xhtml page.
10:00 pm update
Found out that if I instantiate the MailerProject object the same way I don't get the same results I still produce an object full of null attribute values.
Any ideas guys?
Start Here - It'll make the rest of this very trivial.
The Problem
You're using a #RequestScoped bean, and what you're experiencing is the expected behaviour for beans of that scope.
Between the first and the second page, you should understand by now, that you're dealing with two different instances of the editProjects bean : a field you set on the first page, backed by one instance of editProjects will not be available on the destination page, backed by a new instance of editBean.
To Solve
While it wasn't mentioned in the answer I linked to, what you need here is the FlashScope, that serves the express purpose of being transitory in nature: use it just to transport "stuff" between two pages/beans/scopes etc. Sorta. To use:
Declare your undying love for the flash scope around the point of origination of the data. In so doing, you're storing your data in the flash scope object, as implicitly provided by JSF, after which you can then navigate away:
Flash fScope = FacesContext.getCurrentInstance().getExternalContext().getFlash();
fScope.put("editMailer",edit_mailer);
You can then refer to the variable you stored in the flash scope, on the destination page:
<h:outputLabel>#{flash.edit_mailer}</h:outputLabel>
Like I mentioned earlier, the flash scope is a transitory scope: once the destination page has been rendered and the content of the scope displayed, you can consider the data as good as gone. If you would like to hang on to it for just one page redirect longer, you can specify the keep directive:
<h:outputLabel>#{flash.keep.edit_mailer}</h:outputLabel>
Unrelated to the problem
Avoid doing any heavy lifting in a getter/accessor method (like you're doing in getProjectForm). It's bad for business
Why JSF calls getters multiple times
Initialization of List in a JSF Managed bean
What's the significance of returning "1" from that navigation method? Why not "destination_page", or "edit_page.xhtml", y'know, something easier to read? That's just a style thing anyway, no evil can come of that.
I am working on a page with a session-scoped managed bean.
On the page I have a preRenderComponent:
<f:metadata>
<f:event listener="#{pageBean.init}" type="preRenderComponent"></f:event>
</f:metadata>
This page is a template client, that shares a template with some other pages. The template contains a side navigation bar with links to each of the template client pages.
And the page bean:
#Named
#Default
#SessionScoped
public class pageBean implements Serializable {
#PostConstruct
public void init(){
System.out.println("Page Bean init.");
//call methods that populate data on the page
}
}
And the issue occurs as follows:
If I removed the line on the page with preRenderComponent, the pageBean init() method will still be called when the page is accessed.
If I kept the line said above, the init() method will be called when accessed, but it will also be called whenever I clicked on the side navigation bar and accessed another page which uses the same template.
I have referred to this question:CDI bean constructor and #PostConstruct called multiple times
and made sure I was not mixing JSF with CDI, yet this issue still occurs. Though it seems I could resolve this problem by just simply removing the preRenderComponent line, I really wish to understand what is going on here and figure out a way to avoid it in the future.
Any information is much appreciated.
In a previous question BalusC gave me good advice on how a button, in place of a commandButton is useful for non ajax navigation. In particular it updates the destination address in the http: position which is useful for the user to bookmark a page.
I tried to use this information to my advantage until I came upon a problem. In a button I tried to use outcome="#{backing.something}" to find out that it gives me a null result. This looks like a timing problem in that action="#{}" is evaluated only when the button is pressed whereas outcome apparently wants a fixed string which gets checked when the page is loaded.
So I went back to commandButton with ajax="false". This has a problem that my navigation address is the page I came from, not the one I am navigating to. This is the wrong bookmark for the user.
I appreciate all the help I have received in stackoverflow on my learning exercise.
Ilan
The <h/p:button outcome> is not intented to invoke a bean action method, but to contain the outcome string directly. Any EL in there is evaluated immediately as a value expression. So the method behind it would immediately be invoked when you just open the page containing the <h/p:button>.
There are in your particular case basically two ways to invoke a bean action method on navigation. If you need to invoke it before the navigation takes place and the action isn't intented to be re-invoked everytime when the enduser reopens/reloads the GET request, then make it a POST-Redirect-GET request. It's a matter of adding faces-redirect=true to the outcome value in query string syntax.
E.g.
<p:commandButton action="#{bean.submit}" ... />
with
public String submit() {
// ...
return "nextpage?faces-redirect=true";
}
This way the browser will be redirected to the target page after POST, hence the enduser will see the target URL being reflected in the address bar.
Or if you need to invoke the action everytime when the enduser reopens/reloads the GET request, do the job in the (post)constructor or preRenderView listener method of the request/view scoped backing bean instead.
E.g.
<p:button outcome="nextpage" ... />
with
#ManagedBean
#RequestScoped
public class NextpageBacking {
public NextpageBacking() {
// In constructor.
}
#PostConstruct
public void onPostConstruct() {
// Or in postconstructor (will be invoked after construction AND injection).
}
public void onPreRenderView() {
// Or before rendering the view (will be invoked after all view params are set).
}
// ...
}
The pre render view listener method needs to be definied as follows in the nextpage
<f:event type="preRenderView" listener="#{nextpageBacking.onPreRenderView}" />
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
Communication in JSF 2.0 - Processing GET request parameters
I use JSF managed beans calling EJB methods that are provide data from database. I want to use some data already on the welcome page of the application. What is the best solution for it?
EJBs are injected into JSF managed beans and it looks like the injection is done after executing the constructor. So I am not able to call EJB methods in the constructor.
The normal place for EJB call is in the JSF action methods but how to call such a method prior to loding the first page of the application?
A possible solution would be to call the EJB method conditionally in a getter that is used on the welcome page, for example:
public List getProductList(){
if (this.productList == null)
this.productList = myEJB.getProductList();
return this.productList;
}
Is there any better solution? For example, in some config file?
You can do it in a method which is annotated with #PostConstruct. This will be executed once after the bean is constructed and all JSF managed property and resource injection is done.
#PostConstruct
public void init() {
this.productList = myEJB.getProductList();
}
if you want to make a call from xhtml view
<f:view>
<f:metadata>
<f:viewAction action="${myController.init()}" onPostback="true"/>
</f:metadata>
</f:view>
and your controller
public class MyController{
public void init(){
this.productList = myEJB.getProductList();
...