Execute Managebean Method from JavaScript Onload Event

Invoke JSF managed bean action on page load

JSF 1.0 / 1.1

Just put the desired logic in the constructor of the request scoped bean associated with the JSF page.

public Bean() {
// Do your stuff here.
}

JSF 1.2 / 2.x

Use @PostConstruct annotated method on a request or view scoped bean. It will be executed after construction and initialization/setting of all managed properties and injected dependencies.

@PostConstruct
public void init() {
// Do your stuff here.
}

This is strongly recommended over constructor in case you're using a bean management framework which uses proxies, such as CDI, because the constructor may not be called at the times you'd expect it.

JSF 2.0 / 2.1

Alternatively, use <f:event type="preRenderView"> in case you intend to initialize based on <f:viewParam> too, or when the bean is put in a broader scope than the view scope (which in turn indicates a design problem, but that aside). Otherwise, a @PostConstruct is perfectly fine too.

<f:metadata>
<f:viewParam name="foo" value="#{bean.foo}" />
<f:event type="preRenderView" listener="#{bean.onload}" />
</f:metadata>
public void onload() { 
// Do your stuff here.
}

JSF 2.2+

Alternatively, use <f:viewAction> in case you intend to initialize based on <f:viewParam> too, or when the bean is put in a broader scope than the view scope (which in turn indicates a design problem, but that aside). Otherwise, a @PostConstruct is perfectly fine too.

<f:metadata>
<f:viewParam name="foo" value="#{bean.foo}" />
<f:viewAction action="#{bean.onload}" />
</f:metadata>
public void onload() { 
// Do your stuff here.
}

Note that this can return a String navigation case if necessary. It will be interpreted as a redirect (so you do not need a ?faces-redirect=true here).

public String onload() { 
// Do your stuff here.
// ...
return "some.xhtml";
}

See also:

  • How do I process GET query string URL parameters in backing bean on page load?
  • What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
  • How to invoke a JSF managed bean on a HTML DOM event using native JavaScript? - in case you're actually interested in executing a bean action method during HTML DOM load event, not during page load.

How to call a bean method when page loads?

Strange, that should work. Any exceptions? This post contains some alternative ways of achieving what you need. The most standard way should be the first suggestion, to use

<h:body>
<f:ajax event="load" listener="#{bean.onload}" />
</h:body>

with this

public void onload(AjaxBehaviourEvent event) {
// ...
}

Execute method after page has been loaded

JSF is server side, onload is client side. Your only option would be to have the onload fire off an ajax request. See this post for an example.

Execute backing bean action on load?

You can also solve this in JSF 2.0 using component system events, specifically the PreRenderViewEvent.

Just create a download view (/download.xhtml) that fires a download listener before render.

<?xml version="1.0" encoding="UTF-8"?>
<f:view
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core">
<f:event type="preRenderView" listener="#{reportBean.download}"/>
</f:view>

Then, in your report bean (defined using JSR-299), you push the file and mark the response as complete.

public @Named @RequestScoped class ReportBean {

public void download() throws Exception {
FacesContext ctx = FacesContext.getCurrentInstance();
pushFile(
ctx.getExternalContext(),
"/path/to/a/pdf/file.pdf",
"file.pdf"
);
ctx.responseComplete();
}

private void pushFile(ExternalContext extCtx,
String fileName, String displayName) throws IOException {
File f = new File(fileName);
int length = 0;
OutputStream os = extCtx.getResponseOutputStream();
String mimetype = extCtx.getMimeType(fileName);

extCtx.setResponseContentType(
(mimetype != null) ? mimetype : "application/octet-stream");
extCtx.setResponseContentLength((int) f.length());
extCtx.setResponseHeader("Content-Disposition",
"attachment; filename=\"" + displayName + "\"");

// Stream to the requester.
byte[] bbuf = new byte[1024];
DataInputStream in = new DataInputStream(new FileInputStream(f));

while ((in != null) && ((length = in.read(bbuf)) != -1)) {
os.write(bbuf, 0, length);
}

in.close();
}
}

That's all there is to it!

You can either link to the download page (/download.jsf), or use a HTML meta tag to redirect to it on a splash page.

How to call JSF backing bean method using javascript only when The page is loaded

As it turned out you actually want to have a client side cache in localStorage and prevent business logic invocation if that client side cache is valid you
have to go the AJAX way:

I suggest to implement a javascript rendered conditionally which updates the local storage only if needed:

<h:panelGroup id="updateLocalStorageScript" style="display: none;">
<h:outputScript rendered="#{villeBean.updateLocalStorage}">
localStorage.setItem('date',date);
localStorage.setItem('ville', #{villeBean.villesList});
</h:outputScript>
</h:panelGroup>

The update can be triggered by a command action as proposed here: How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?

<h:form id="frmHidden" style="display: none;">
<h:commandButton id="cmdDoUpdateLocalStorage" action="#{villeBean.doUpdateLocalStorage()}">
<f:ajax execute="@this" render=":updateLocalStorageScript" />
</h:commandButton>
</h:form>

Of course you can also use p:remoteCommand, the OmniFaces solution or other suggestions proposed in above QA.

This command action leads to the javascript being rendered and initializes the list value by invoking your business logic only once.

@ManagedBean (name="villeBean)"
@ViewScoped
public class Villes {
private boolean updateLocalStorage;

private String villesList;

public void doUpdateLocalStorage() {
updateLocalStorage = true;
villesList = dao.listeVilles();
}

public boolean isUpdateLocalStorage() {
return updateLocalStorage;
}

public String getVillesList() {
return villesList;
}

}

Trigger that command from within your javascript conditional blocks:

if(localStorage['ville'] == null || localStorage['date']==null){
document.getElementById('frmHidden:cmdDoUpdateLocalStorage').onclick();
}
else{
var oldDate = new Date(localStorage['date']).getTime();;
var currentDate = new Date().getTime();
var distance = currentDate - oldDate ;
var days = Math.floor(distance / (1000 * 60 * 60 * 24));
if (days >= 15){
document.getElementById('frmHidden:cmdDoUpdateLocalStorage').onclick();
}
}

How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?

Several ways.

  1. Use <h:commandScript>. Note that this is only available since JSF 2.3.

    <h:form>
    <h:commandScript name="commandName" action="#{bean.action}" render=":results" />
    </h:form>
    <h:panelGroup id="results">
    ...
    </h:panelGroup>

    You can invoke it in JS as below:

    commandName();

    The parameters can be passed as below:

    commandName({ name1: "value1", name2: "value2" });

    And obtained as below:

    String name1 = externalContext.getRequestParameterMap().get("name1"); // value1
    String name2 = externalContext.getRequestParameterMap().get("name2"); // value2

    To invoke it during load event, set autorun="true".

    <h:commandScript ... autorun="true" />

  2. If you're using PrimeFaces, use its <p:remoteCommand>.

    <h:form>
    <p:remoteCommand name="commandName" action="#{bean.action}" update=":results" />
    </h:form>
    <h:panelGroup id="results">
    ...
    </h:panelGroup>

    You can invoke it in JS as below:

    commandName();

    This however doesn't use JSF native jsf.ajax.request(), instead it uses PrimeFaces native jQuery (you know, PrimeFaces is a JSF component library on top of jQuery/UI).

    The parameters can be passed as below:

    commandName([{ name: "name1", value: "value1" }, { name: "name2", value: "value2" }]);

    And obtained as below:

    String name1 = externalContext.getRequestParameterMap().get("name1"); // value1
    String name2 = externalContext.getRequestParameterMap().get("name2"); // value2

    To invoke it during load event, set autoRun="true".

    <p:remoteCommand ... autoRun="true" />

  3. If you're using OmniFaces, use its <o:commandScript>. The usage is exactly the same as with <h:commandScript> but then available for older JSF 2.x versions.

    Simply replace h: by o: in the first example. Historical note: the <h:commandScript> is entirely based off <o:commandScript>.


  4. Use the "hidden form" trick (actually, "hack" is given the ugliness a better wording).

    <h:form id="form" style="display:none;">
    <h:commandButton id="button" action="#{bean.action}">
    <f:ajax render=":results" />
    </h:commandButton>
    </h:form>
    <h:panelGroup id="results">
    ...
    </h:panelGroup>

    You can invoke it in JS as below:

    document.getElementById("form:button").onclick();

    Note the importance of triggering onclick() instead of click() in case of <h:commandButton>. The onclick() immediately invokes the onclick function while the click() only triggers the "click" event on the element, which is not supported in IE. If you were using a <h:commandLink>, you can safely use click() instead.

    You can pass parameters via <h:inputHidden> in same form which you fill by JS beforehand. This is demonstrated in How to pass JavaScript variables as parameters to JSF action method?

    To invoke it during load event, consider putting it in <h:outputScript target="body">. The target="body" automatically puts the <script> in end of <body>, thus a $(document).ready() wrapper is unnecessary.

    <h:outputScript target="body">
    document.getElementById("form:button").onclick();
    </h:outputScript>

  5. Or, create a custom UIComponent which extends UICommand and generates the necessary JSF native jsf.ajax.request() call. As an example you could look at source code of OmniFaces <o:commandScript>.

How to call JSF backing bean method only when onclick/oncomplete/on... event occurs and not on page load

This approach will not work. You seem to be confusing/mixing the basic web development concepts of the "server side" and "client side" and to be misunderstanding the role of JSF and EL.

JSF is a server side language which runs on the webserver upon a HTTP request and produces HTML/CSS/JS code which get returned with the HTTP response. All EL expressions in form of ${} and #{} will be executed in the server side during generating the HTML output. JavaScript is a client side language which runs on the webbrowser and works on the HTML DOM tree. The HTML onclick attribute should specify a JavaScript function which will be executed in the client side on the particular HTML DOM event.

In order to invoke a JSF managed bean method, you need the action or *listener attribute. JSF provides components to generate the desired HTML and specify the desired ajax actions which would change the server side state. An <input type="image"> can be generated using a <h:commandButton image>. A bean method can be invoked by the action attribute of that component. That component can be ajaxified by embedding the <f:ajax> tag.

So, the following should do it for you:

<h:form>
<div class="sidebarOptions">
<h:commandButton image="images/homeButton.jpg" action="#{home.setRendered(1)}">
<f:ajax execute="@this" render=":sidebar" />
</h:commandButton>
</div>
<div class="sidebarOptions">
<h:commandButton image="images/memberButton.jpg" action="#{home.setRendered(2)}">
<f:ajax execute="@this" render=":sidebar" />
</h:commandButton>
</div>
</h:form>

<!-- The below is just a guess of what you're really trying to achieve. -->
<h:panelGroup id="sidebar" layout="block">
<h:panelGroup rendered="#{home.rendered eq 1}">
Home
</h:panelGroup>
<h:panelGroup rendered="#{home.rendered eq 2}">
Member
</h:panelGroup>
</h:panelGroup>

See also:

  • Differences between action and actionListener
  • How to invoke a managed bean action method in on* attribute of a JSF component
  • How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?


Related Topics



Leave a reply



Submit