 |
March 2006 Archives
AJAX I18n with Java
Posted by gmurray71 on March 13, 2006 at 04:13 PM | Permalink
| Comments (7)
Internationalization (i18n) is easy if you are using AJAX and Java. Both Java and JavaScript have i18n capabilities though it is not obvious how to use those capabilities are not from an i18n background.
I have re-worked the Realtime Validation with AJAX example to be i18n enabled. Follow these steps on the client and server to support i18n.
On the client:
- Set the content-type in your pages to UTF-8
UTF-8 is the recommended encoding as it supports the widest range of languages.
- From JavaScript call encodeURIComponent() on localized form parameters.
This is a built in JavaScript function that will make sure form variables are encoded in an HTTP friendly way. The encoding scheme used matches the charset used in the content-type of the page.
The following JavaScript snippet gathers form information to send back to the server in an AJAX request. Note the sections marked in red.
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
...
function validateUserId() {
if (!target) target = document.getElementById("userid");
var url = "validate?id=" + encodeURIComponent(target.value);
var target = document.getElementById("userid");
var ajax = new AJAXInteraction(url, validationCallback);
ajax.doGet();
}
function validateCallback(responseXML) {
var msg = responseXML.getElementsByTagName("valid")[0].firstChild.nodeValue;
if (msg == "false"){
var mdiv = document.getElementById("userIdMessage");
// set the style on the div to invalid
mdiv.className = "bp_invalid";
mdiv.innerHTML = "Invalid User Id";
var submitBtn = document.getElementById("submit_btn");
submitBtn.disabled = true;
} else {
var mdiv = document.getElementById("userIdMessage");
// set the style on the div to valid
mdiv.className = "bp_valid";
mdiv.innerHTML = "Valid User Id";
var submitBtn = document.getElementById("submit_btn");
submitBtn.disabled = false;
}
}
</script>
...
<input type="text"
size="20"
id="userid"
name="id"
autocomplete="off"
onkeyup="validateUserId()">
<div id="userIdMessage"></div>
On the server:
- Call request.setCharacterEncoding("UTF-8") before getting any parameters.
We know this is the correct encoding because we set it as the content type of the page.
- Set the content-type on the response to "UTF-8" if it contains localized content.
Event though the defualt encoding of XML is UTF-8 don't assume the conent will be encoded in UTF-8. Set the response content type using the servlet method response.setContentType where the content-type is followed by the encoding used for the response. In this case use "charset=UTF-8".
The following servlet interacts with an internationalized AJAX client. Once again the i18n specific portions are marked in red.
public class ValidationServlet extends HttpServlet {
private ServletContext context;
private HashMap accounts = new HashMap();
public void init(ServletConfig config) throws ServletException {
super.init(config);
this.context = config.getServletContext();
accounts.put("greg","account data");
accounts.put("duke","account data");
// add a Japanese hiragana example "ne" "ko" (cat)
accounts.put("\u306D\u3053","account data");
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
String targetId = request.getParameter("id");
if ((targetId != null) && !accounts.containsKey(targetId.trim())) {
response.setContentType("text/xml;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<valid>true</valid>");
} else {
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
response.getWriter().write("<valid>false</valid>");
}
}
}
That is pretty much it. This example the Japanese hiragana characters
"ねこ" are a reserved user id. The image below shows the example running.
Find the code and more about this example at Realtime Validation with AJAX.
JavaScript Recomendations for AJAX Component Writers
Posted by gmurray71 on March 08, 2006 at 02:00 PM | Permalink
| Comments (13)
With AJAX there are many choices on how to use different aspects of JavaScript. Here are some recommendations we came up with for using JavaScript with the focus on creating AJAX components that will interact with a Java technology based server. Each of these recommendations is linked to a larger document that contains more details and in many cases code samples.
- Use JavaScript Programming Conventions
Standardize style makes code easy to work with and maintain especially in larger organizations. See the
of JavaScript Programming Conventions created
by the Dojo folks.
- Use object oriented JavaScript
Writing object orient JavaScript will allow for code re-use, enables you or others to extend your
objects, and allows your scripts to be loaded and initialized dynamically.
- Use object hierarchies to organize JavaScript objects
When writing components use objects and object hierarchies to organize related
objects and prevent naming collision.
- Use the prototype property to define shared behavior and to extend objects
Use the prototype property to extend, add functionality, or provide defaults to your objects. Use the prototype property to define shared functions (behavior)
across instances of an object as it will reduce the number of objects in JavaScript and its use provides a good separation of behavior from data.
- Store state specific to the view in JavaScript and
state that span pages on the server
Store view state related to a specific page using JavaScript objects. Keep in mind that
JavaScript objects are specific to a HTML page and will be lost if the "Reload" button
is pressed, if the browser is relaunched/crashes, or if you navigate to another page.
Store state that spans pages on the server as Java objects scoped to the HttpSession.
The client and server objects should be synched on page refreshes and page loads.
- Write reusable JavaScript
JavaScript should not be tied to a specific
component unless absolutely necessary. Consider parameterizing data in your functions instead of hard coding the data.
- Use object literals as flexible function parameters
Object literals are very handy in that they can be used as generic for passing in arguments to a function.
Since the function signature does not change if you choose to require more properties in a function, consider using an object literal as the parameter for a function.
- Compress your JavaScript
Not to be confused with a zip compression
scheme compression refers to removing the white spaces and shortening the names of variables and functions
in a file. Consider compressing your JavaScript resources when you deploy your application.
- Do not compress your Jar files that contain your scripts
Do not use zip compression on jar files with scripts or styles that are served by a server side component. Compressing those jars
will cause the server to decompress the file for each client request for the script or resource. Larger scripts could cause performance problems for your server.
- Protect your server side assets
Never put business logic or server-side access code in JavaScript. Always validate request parameters on the server
regardless of whether the request originated from an AJAX client or not.
- Consider loading JavaScript on demand
JavaScript may be loaded dynamically at runtime using a library such as JSAN or done manually by using AJAX to load JavaScript code and calling eval() on the JavaScript. This is useful if you have a large library or set of libraries.
- Consider using JSON for model data transport
While the XML is still a
valid format for model data transport in AJAX (especially in cases where you're communicating with XML based services or your
services must also address non-AJAX based clients), you should consider using JSON to communicate
data from your server to your JavaScript based client.
- Provide a clean separation of content, CSS, and JavaScript
A rich web application user interface is made up of content (HTML/XHTML), styles (CSS), and JavaScript. JavaScript is invoked by user gestures such as mouse clicks and can manipulate the content. Separating the CSS styles from the JavaScript is a practice which will make your code more manageable, easier to read, and easier to customize. It is recommended that the CSS and JavaScript are placed in separate files.
- Avoid static content in JavaScript
Keep the amount of static HTML/XHTML content in JavaScript to a minimum. This will make managing the source and updating static content easier. You may want the content in your components updateable without changing your source.
- Use caution with
element.innerHTML
If you choose to use element.innerHTML try to write JavaScript that
generates minimal HTML. Rely instead on CSS for enhancing the presentation. Remember
to always strive to separate content from presentation. Make sure to de-register event listeners
in the existing innerHTML of the element before re-setting the element.innerHTML
as it will lead to memory leaks. Keep in mind that instances of DOM elements inside the element.innerHTML are lost when you replace
the content and references to those elements will be lost as well.
- De-reference unused objects
Make sure you de-reference variables when they are no longer needed so they may be garbage collected.
If you are using element.innerHTML, make sure you de-reference any listeners in the code before it is replaced.
- Use care with closures
If you use closures take caution not to hold on to references to browser objects such as DOM related objects using the local variables of a closure as this can lead to memory leak. Objects are not garbage collected until all references to objects are gone. Make sure you understand closures in order to avoid creating them accidentally.
- Enable resource overrides in your components
Provide a means to override the loading of resources such as dependent scripts, CSS files, or
images by your JavaScript centric, JSP, Servlets, or JSF components. If you
jar your component for distribution with a JSP tag or JSF component, move those resource files into the
WEB-INF directory and create code to stream them out to the client. This will
allow your customers to customize the component styles or JavaScript on a case by case basis
without rebuilding and re-packaging the component.
- Design with I18n in mind
Internationalization should not be an after thought. From the JavaScript client's
perspective you need to do two things: Set the page encoding and make sure localized text is passed back to your
server backend. Consider using XML as the return content type for localized data as XML can specify encoding
information that is understood and applied by the XMLHttpRequest object. If you are passing around
localized content you need to make sure you server encodes the return content properly.
What would you add to the list?
|