Monday, May 25, 2009

Java/JSP/JSF and JavaScript

Introduction

Today I investigated using Google Analytics the search keywords used to find this blog, so that I can get some blogging inspiration based on the "missing hits" (i.e. the actual search incorrectly showed my blog between the results). Just for fun I entered "javascript" in the Analytics keyword-search tool to see what happens. To my surprise I see that fairly a lot of Google search keywords in the following context were used:

  • access jsf managed bean in javascript
  • javascript pass variable to jsp
  • check jsf facesmessages in javascript
  • call java method in javascript
  • set javascript variable in jsp
  • communicate jsf and javascript

There's apparently still a lot of confusion and unawareness in the (young) web developer world with regard to Java/JSP/JSF and JS. Well, let's write a blog about it to clear it all out.

Back to top

Server side and client side

You probably have ever heard of "server side" and "client side" in terms of web development. You have server side specific technologies and programming languages and also client side specific technologies and programming languages (well, not specifically programming, it's in terms of web development more scripting and markup, but OK, let's make it easy understandable).

When one develops websites, one would often use physically the same machine (PC, laptop, whatever) to develop and test websites on. I.e., both the webserver and webbrowser runs at physically the same machine. This would never, I repeat, never occur in real production world. The server machine and the client machine are always physically different machines, connected with each other by some kind of a network (usually the Internet).

Java/JSP/JSF are server side specific technologies. It runs at the server machine and produces HTML/CSS/JS output based on a HTTP request of the client machine. This output will be sent over network from the server side to the client side as part of the HTTP response. Open up such a JSP/JSF page in your favourite webbrowser and choose the "View Source" option (or something similar). What do you see? Right, it's all plain vanilla HTML/CSS/JS. If the code at the server side has done its task the right way, you should not see any line of Java/JSP/JSF code in the generated output.

When the server application (in this case, the webserver) has sent the output, it has finished its task of HTTP request/response cycle and is now waiting for the next HTTP request from the client side. When the client application (in this case, the webbrowser) has received the HTML/CSS/JS output, displayed the HTML, applied the CSS and executed any "onload" JS, it has finished its task of showing the result of some client interaction (entering URL in address bar, clicking a link, submitting a form, etcetera) and is now waiting for the next client interaction to fire a new HTTP request for.

JS is a client side specific technology. It runs entirely at the client machine and it only has direct access to the whole HTML DOM tree (the stuff which is accessible through the document object). It would only get executed directly when the client application (the webbrowser) encounters inline JS code or onload events during loading of the page for display. It can also get executed later when the client application receives specific events which have a JS function attached, such as onclick, onkeypress, onmouseover, etcetera. All of those events can be specified as HTML element attributes.

You should now realize that the only way to let Java/JSP/JSF at the server side pass variables to or execute something at the client side is simply by generating the HTTP response for the client side that way so that the JS action will be taken accordingly. You should also realize that the only way to let JS at the client side pass variables to or execute something at the server side is by simply firing a new HTTP request to the server side that way so that the Java/JSP/JSF action will be taken accordingly.

Back to top

Pass variables from server side to client side

As you might have understood now, this can only happen by writing inline JS code or onload events accordingly. Let's check first how the generated HTML output should look like then:

<!doctype html>
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript">
            // Do something inline with variable from server.
            var variableFromServer = 'variableFromServer';
            doSomethingInline(variableFromServer);
            function doSomethingInline(variable) {
                alert('doSomethingInline: ' + variable);
            }

            // Do something onload with variable from server.
            function doSomethingOnload(variable) {
                alert('doSomethingOnload: ' + variable);
            }
        </script>
    </head>
    <body onload="doSomethingOnload('variableFromServer');">
        <h1>Test</h1>
    </body>
</html>

The above is just a basic example, you could also use for example an onclick event instead. OK, in the place of variableFromServer we thus want to set a variable from the server side. You can just do it by writing the server side code accordingly that the desired generated HTML output is exact the same as above. Let's suppose that the variable have to be retrieved as a bean property. Here's an example with JSP:

<!doctype html>
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript">
            // Do something inline with variable from server.
            var variableFromServer = '${someBean.someProperty}';
            doSomethingInline(variableFromServer);
            function doSomethingInline(variable) {
                alert('doSomethingInline: ' + variable);
            }

            // Do something onload with variable from server.
            function doSomethingOnload(variable) {
                alert('doSomethingOnload: ' + variable);
            }
        </script>
    </head>
    <body onload="doSomethingOnload('${someBean.someProperty}');">
        <h1>Test</h1>
    </body>
</html>

Fairly simple, is it? Take note that you still need those singlequotes around the variable; not for Java/JSP, but for JavaScript! Only pure number or boolean variables can be left unquoted.

In JSF the principle is not that much different. You could use EL the same way, but if it has to be retrieved as a managed bean property and you're using JSF on JSP, you can just use h:outputText instead to output it. Here's an example:

<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<!doctype html>
<f:view>
    <html>
        <head>
            <title>Test</title>
            <script type="text/javascript">
                // Do something inline with variable from server.
                var variableFromServer = '<h:outputText value="#{someBean.someProperty}" />';
                doSomethingInline(variableFromServer);
                function doSomethingInline(variable) {
                    alert('doSomethingInline: ' + variable);
                }

                // Do something onload with variable from server.
                function doSomethingOnload(variable) {
                    alert('doSomethingOnload: ' + variable);
                }
            </script>
        </head>
        <body onload="doSomethingOnload('<h:outputText value="#{someBean.someProperty}" />');">
            <h1>Test</h1>
        </body>
    </html>
<f:view>

Run the page and check the generated HTML output. Do you see it? That's the whole point! This way you can let JS "access" the server side variables. When you're using JSF on Facelets, then you can just leave the h:outputText away and use #{someBean.someProperty} instead since Facelets supports unified EL in template text.

In the code examples the JS code will be executed two times. The first time when the line with the inline JS function call is interpreted by the client application and the second time when the page is loaded completely (the body onload attribute). The biggest difference is that the second function will only be executed when the entire HTML DOM tree is built up, this is important if the function require HTML DOM elements which are to be obtained by the document reference in JS.

Back to top

Pass variables from client side to server side

As you probably already know, you can do that with plain HTML by just clicking a link with query parameters, or submitting a form with (hidden) input parameters. Links sends HTTP GET requests only, while forms are capable of sending HTTP POST requests. In JS, on the other hand, there are in general three ways to accomplish this:

  1. The first way is to simulate invocation of an existing link/button/form. Here are three examples:
    <a id="linkId" href="http://www.google.com/search?q=balusc">Link</a>
    
    ...
    
    <script type="text/javascript">
        document.getElementById('linkId').click();
    </script>
    
    <form action="http://www.google.com/search">
        <input type="text" id="inputId" name="q">
        <input type="submit" id="buttonId" value="Button">
    </form>
    
    ...
    
    <script type="text/javascript">
        document.getElementById('inputId').value = 'balusc';
        document.getElementById('buttonId').click();
    </script>
    
    <form id="formId" action="http://www.google.com/search">
        <input type="text" id="inputId" name="q">
    </form>
    
    ...
    
    <script type="text/javascript">
        document.getElementById('inputId').value = 'balusc';
        document.getElementById('formId').submit();
    </script>
    
    In case of JSF, keep in mind that you must use the element ID's of the JSF generated HTML elements (the JSF Client ID's) in JS. Those are namely not necessarily the same as JSF component ID's! So, view the generated HTML output when writing JS code specific for JSF output. For example the following JSF code..
    <h:form id="formId">
        <h:inputText id="inputId" value="#{bean.property}" />
        <h:commandButton id="buttonId" value="Button" action="#{bean.action}" />
    </h:form>
    
    ..would produce roughly the following HTML output..
    <form id="formId" action="current request URL">
        <input type="text" id="formId:inputId" name="formId:inputId" />
        <input type="submit" id="formId:buttonId" name="formId:buttonId" value="Button" />
    </form>
    
    ..for which you should write JS like the following:
    <script type="text/javascript">
        document.getElementById('formId:inputId').value = 'foo';
        document.getElementById('formId:buttonId').click();
        // Or: document.getElementById('formId').submit();
    </script>
    
  2. The second way is to use window.location to fire a plain GET request. For example:
    <script type="text/javascript">
        var search = 'balusc';
        window.location = 'http://www.google.com/search?q=' + search;
    </script>
    
  3. The third way is to use XMLHttpRequest object to fire an asynchronous request and process the results. This technique is the base idea of "Ajax". Here's a Firefox compatible example:
    <script type="text/javascript">
        function getUrl(search) {
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4) {
                    var responseJson = eval('(' + xhr.responseText + ')');
                    var url = responseJson.responseData.results[0].unescapedUrl;
                    var link = document.getElementById('linkId');
                    link.href = link.firstChild.nodeValue = url;
                    link.onclick = null;
                }
            }
            var google = 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q='
            xhr.open('GET', google + search, true);
            xhr.send(null);
        }
    </script>
    
    ...
    
    <p>My homepage is located at: <a id="linkId" href="#" onclick="getUrl('balusc')">click me!</a></p>
    
    Funny, is it? You didn't see a "flash of content" (reload/refresh) because it all happens fully in the background. That's the nice thing of Ajax. For compatibility with certain webbrowsers which uses proprietary API's (cough) you'll need to write some supplementary code. Also see the Ajax tutorial at w3schools.

    In case of JSP, it's better to start with a widely used Ajaxical API than reinventing the wheel by writing it yourself, which would at end only lead to trouble in terms of maintainability and reusability. I highly recommend to take a look for the great jQuery API. Its replacement of the getUrl() would then look something like:
    function getUrl(search) {
        var google = 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=';
        $.getJSON(google + search, function(responseJson) {
            var url = responseJson.responseData.results[0].unescapedUrl;
            $('#linkId').attr('href', url).text(url).attr('onclick', null);
        });
    }
    
    On the server side, instead of the Google example you could of course create a Servlet which has doGet() implemented and returns for example a JSON string so that JS could process it further. JSON is a shorthand for JavaScript Object Notation. It is roughly a blueprint of a JavaScript object in String format. You can even specify and access object properties. In the eye of a Java developer, a JSON has much Javabean characteristics. If you're new to JSON (or even JavaScript or HTML DOM), here are more tutorials: JavaScript, HTML DOM and JSON. For converting Java objects to a JSON string which you just write to response, I can recommend the GSON API.
    
        /**
         * Write given Java object as JSON to the output of the given response.
         * @param response The response to write the given Java object as JSON to its output.
         * @param object Any Java Object to be written as JSON to the output of the given response. 
         * @throws IOException If something fails at IO level.
         */
        public void writeJson(HttpServletResponse response, Object object) throws IOException {
            String json = new Gson().toJson(object);
            response.setContentType("application/json");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(json);
        }
    
    

    In case of JSF, just take a look for Ajaxical component libraries such as JBoss RichFaces. It provides "supplementary" Ajax support in form of the Ajax4jsf (a4j) components, also see this document.

Hopefully it's now all clear what the whole point of "server side" and "client side" is and what their capabilities are.

Happy coding!

Back to top

Copyright - No text of this article may be taken over without explicit authorisation. Only the code is free of copyright. You can copy, change and distribute the code freely. Just mentioning this site should be fair.

(C) May 2009, BalusC

26 comments:

Kishore said...

Excellent one :)

Aaron said...

The man produces the goods once again! Started JSF 6 months ago Balus, don't know how I'd have managed without your blog. Many many thanks.

U.A.S said...

Hi!
Sorry to bother you, but I was wondering...
In Pass variables from client side to server side, if I use the first approach "Simulate invocation of an existing link/button/form. For example: "... What should I put in the "action" attribute of form if I want to stay in the same page but with reloaded content?

BalusC said...

Just the same URL as the current request URL. You can even leave it away, the browser will assume the current request URL as action URL.

Anupriya Srivastava said...

excellent

Unknown said...

very good explaination

beast said...

Nice post but I have a question that might require a workaround I haven't figured out yet. My action attribute already has an entry that is linked to my faces-config and redirects the page. However, I need to instruct the page to run a backing bean method as well (what an actionListener does). However I can only fire the onclick method via javascript which ignores the actionListener command. Any ideas?

beast said...

just to add...i know i could set my backing bean method as the action attribute and return the view to be displayed but i have different buttons calling the same backing bean methods but going to different views. i'm trying to find a solution without breaking my current structure if possible

BalusC said...

You need to execute the button in question by button.click().

beast said...

For some reason when executing the button.click() command I thought the backing bean method in the actionListener attribute wasn't being run. I just realized it was and I just wasn't debugging it right. Thanks though.

Unknown said...

Hi,

I have the following requirement in jsf.

on click of check box I should disable the validation of the input textbox (i.e., I should make required value as "true" or "false" based on the value of check box clicked). Please tell me how can I do this one??
thanks in advance.

Unknown said...

Excellent articles. Balu, I found your blog is very helpful in JSF area. I need favor from you on writing custom ajax supported jsf components.

I cant use ajax4jsf library though it comess under freeware. I need components like ajax4jsf:poll. Could you please help me to write that. I would really appreciate if you help me on this.

Thx
rup

Vamshidhar Reddy Boda said...

Wonder full...elucidation with great clarity! Thanks BalusC for spreading the knowledge

Unknown said...

Its nice concept. Similary i want to explore the bean list value in java script.I have developing jsf application. i want to show alert message (bean List values). The beanlist values (using arrayList) in backend. Any sample code available or notes.Help me.Thanks in advance

Remya said...

How can i call a backing bean method from javascript?
for example if i have a method doSomthing() in managed bean,
is it possible for me to call it some way from javascript?
Even setting a property value i showing errors..ex:if i give
'#{someBean.someProperty}'='true';i am getting an error cannot assign [string]
Please give your suggestion about this..thank you

waheeb said...

Hi, I am looking forward to pass the value of one jsf page to another.
I am trying to use javascript but I am unable to pass it to the processAction method.
I have posted the query on stackoverflow.
http://stackoverflow.com/questions/7362752/transfer-data-from-one-jsf-page-to-processaction-method-of-facesportlet
Any idea how this can be done?

subbu said...

Hey Balu,

Nice article. I was wondering if we could over-ride the default jsf.js that JSF uses to produce all the JS for all its AJAX enabled controls. So that I could use something like jQuery as the default JS underneath and extend the behavior for a more controlled environment. Not sure if you are aware of how Tapestry framework is built. I was wondering if we could do something similar with JSF.

Amerant said...

Hey! When I tried your approach and passed this :onload="doSomethingOnload('');"> , I got this error:
0000009d WebApp E [Servlet Error]-[Faces Servlet]: java.lang.ClassCastException: com.ibm.ws.jsf.application.WSViewRoot incompatible with javax.faces.component.UIOutput
at com.sun.faces.taglib.html_basic.OutputTextTag.setProperties(OutputTextTag.java:87)
at javax.faces.webapp.UIComponentTag.findComponent(UIComponentTag.java:719)
at javax.faces.webapp.UIComponentTag.doStartTag(UIComponentTag.java:436)
at com.sun.faces.taglib.html_basic.OutputTextTag.doStartTag(OutputTextTag.java:181)

ISC Hana Lara said...

Thank you very much! I'm your fan :)

Bouke van der Spoel said...

Well, I got here on googling "javascript jsf interaction". However, i'm not interested in interacting with the server, but interacting with the generated code from my own javascript code. The issue i currently have is that a call to [a RichFaces contextmenu].hide() triggers a refresh of the page. I was wondering if anything could be said in general about this kind of interaction. Or are these generated components best regarded as black boxes?

Aaron said...

When I've used "formId:inputId" in javascript I've had to escape the : character. e.g. "formId\\:inputId"

BalusC said...

@Aaron, no you only need to do that in CSS selectors, like as used by jQuery. In normal JS document.getElementById(id) you don't need to do that. However, in jQuery $("#id") which takes a CSS selector, you indeed need to escape it. See further also:

- By default, JSF generates unusable ids, which are incompatible with css part of web standards
- How to select PrimeFaces UI or JSF components using jQuery?
- How to use JSF generated HTML element ID in CSS selectors?

AarthiArun said...

hi im new to jasf amg im using jsf1.2 and ajax in ee5.

i have a cmd button like tis in export.jsp page,



when i click on the button, i have to fetch the beanvalue and only when it is true , export.jsp gets updated with the content from hello.jsp using ajax.

can you pls help me with the samplecode. thank you!

Unknown said...

Thanks a ton!!

U just saved the day.. with this article..

Cheers!!

GOPI said...

Hi ,
Thanks alot for this informative article on JSF and JS..

I am just a bit confused with the below scenario,
I have a list in the backing bean, I am trying to display it as a Table in the UI, and I want to add a remove button on each row, when I click on the remove button, I need to set a variable in the backing bean and then call a function. Can you guide me how to go about this.

Thanks,
Gopi

AdrienBe said...

Hi BalusC, it's actually the first time that I totally disagree on your solution regarding "Pass variables from server side to client side". Using things such as "onload" attributes is really ugly. Considering the much cleaner options available to us. I elaborate my point in this answer http://stackoverflow.com/a/23823951/759452
Interesting article though, as usual :)