How to invoke a JSF managed bean asynchronously through JavaScript
Sometimes great frameworks like JSF, Wicket or Spring MVC make simple tasks surprisingly difficult to do. With JavaServer Faces, the simple task of invoking a method on a managed bean is actually a bit of a chore. In this tutorial, we tackle that chore together.
One of the most frustrating aspects of using a web framework like Wicket, Spring MVC or JavaServer Faces (JSF) is the fact that sometimes simple tasks become extremely challenging, and solutions to what should be an easy problem to solve take disturbingly non-obvious turns. A friend recently posed a development problem to me that had a two prong solution, with the first prong being the invocation of a JSF backing bean through a JavaScript call. You’d think this first prong would be relatively straight forward, but frustratingly, it’s not.
Calling a standard backend resource such as a Servlet or a JSP is a pretty simple task. After all, every JSP and Servlet has a fully qualified name through which it can be referenced. On the other hand, methods of JSF managed beans are not invoked in the same traditional way. Methods of JSF managed beans need to be invoked through JSF UI components such as a commandLink or a commandButton. And you can’t just make those components magically appear inside of a JavaScript method.
Coding up the first-prong.xhtml page
To solve this little problem, the first thing you need to do is put a JSF command component on your page, and wrap it up with all of the appropriate h:form elements and JSF tag references. This following is the code for the first-prong.xhtml page:
<html lang="en" xmlns="https://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"> <h:body> <h:form id="form"> <h:commandLink id="link" action="#{myManagedBean.doSomething}" value="click"/> </h:form> </h:body> </html>
Coding up the managed bean
Getting back to basics, the important part of this whole thing is the commandLink with the name of link and the action attribute which calls the doSomething method of the managedBean. Accordingly, we’ll need to create a JavaBean called ManagedBean and a corresponding method named doSomething. Here’s how it looks:
package com.mcnz.jsf; import javax.faces.bean.*; @ManagedBean @ViewScoped public class MyManagedBean { public void doSomething() { System.out.println("doSomething method called."); } }
At this point in time, it’s a good idea just to run the code and make sure everything is glued together properly. If you can’t successfully invoke your doSomething method using standard JSF tags and managed beans, you’re definitely not going to have any success invoking the bean using JavaScript. When you run the program, there are no page transitions or anything. All you will see is a happy little message in the output window of your IDE stating: "doSomething method called."
So how can you call the doSomething method of myManagedBean through JavaScript? Well, the first step is to figure out what the name of your commandLink is when it is rendered on the web. The standard naming is to simply daisy chain the form name to the commandLink, giving the component the name form:link. Of course, if you’ve buried the link within PanelGroups or other DOM elements, the depth of the daisy chaining might be much deeper. Or, you have set up your JSF application not to chain component names together at all, making the name simply the id of the commandLink. Just be sure by doing a view-source on the first-prong.xhtml page when it renders in the browser to verify that you have the correct component name.
Sprinkling in some JavaScript
With the basic JSF components working, it’s time to wire in some JavaScript to call that commandLink, which in turn will call the managed bean. The magic is really nothing more than going through the DOM of the web page, grabbing the JSF commandButton and invoking the click method on it:
<script type="text/javascript" > function invokeCommandLink() { var jsfCommandLink = document.getElementById("form:link"); jsfCommandLink.click(); } </script>
That’s the script. Now we need something to invoke the script, which could be anything, but we’re just going to use a plain, old, HTMLM anchor link with its onclick method pointing at the invokeCommandLink JavaScript method:
<a onclick="invokeCommandLink()">Anchor Link</a>
The managed bean hasn’t changed at all, so nothing needs to be disturbed as far as Java code goes. The complete xhtml page looks as follows:
<html lang="en" xmlns="https://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"> <h:body> <h:form id="form"> <h:commandLink id="link" action="#{myManagedBean.doSomething}" value="click"/> </h:form> <a onclick="invokeCommandLink()">Anchor Link</a> </h:body> <script type="text/javascript" > function invokeCommandLink() { var jsfCommandLink = document.getElementById("form:link"); jsfCommandLink.click(); } </script> </html>
Going asynchronous
When the code is redeployed and tested, the anchor link now invokes the managed bean by going through the JSF commandButton. It’s a little bit of razzle dazzle, but it works pretty reliably, and that’s really all we expect from our software.
By the way, we could make two little adjustments to make things just a little better in our application. First, we can add a style to completely hide the commandLink, and also remove the value attribute. After all, there’s really no reason to show it:
<h:commandLink style="display:none" id="link" action="#{myManagedBean.doSomething}"/>
Secondly, we can make the method call happen asynchronously by using a commandButton instead of a commandLInke, and using the f:ajax tag:
<h:commandButton style="display:none" id="link" action="#{myManagedBean.doSomething}"> <f:ajax/> </h:commandButton>
And that’s all there is to it. It’s not completely intuitive, but it’s functional, and functional is good.
Do you have a better way to invoke a JSF managed bean? Let us know.
You can follow me, Cameron McKenzie, on Twitter: @potemcam
Dig Deeper on Front-end, back-end and middle-tier frameworks
-
Ajax, JavaScript support and CDI alignment tops the list of what's new in JSF 2.3
-
Asynchronously invoking a second managed bean method in JavaSever Faces (JSF)
-
JSF Tutorial: Completing the Ajax based Facelets application
-
Integrating Ajax into your Facelets pages: Death to JSF's request-response cycle