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:
- 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>
- 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>
- 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