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

ajax, facelets, javascript, jsf, primefaces

Solution

Several ways.

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

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

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>`.

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()`. The `onclick()` immediately invokes the generated `onclick` function, while the `click()` basically only simulates the "click" action on the element, as if a mouse is used, which is not supported in IE, and in some browsers also require the element being actually interactable (i.e. `display:none` can't be used then).

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>

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>`.

Problem

I need to execute a JSF managed bean action method using ajax during HTML DOM `load` event, similar to jQuery's `$(document).ready(function() { $.ajax(...) })`. I can only use the JavaScript generated by JSF in this project. Is there a way to do it in native JSF? Which event can I use or which JSF ajax function can I use? I'm using JSF 2.0, Facelets and PrimeFaces.

Original source

Related problems