Archive for September, 2006

Create checked radio button dynamically

Written by coregps on Friday, September 22nd, 2006 in AJAX, Web Design.

If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

I meet some trouble when creating radio buttons through javascript. My code is something like this:

function createRadioButton(elt_name, elt_value, elt_label, is_selected) {
    var inputElement = document.createElement('input');
    inputElement.setAttribute('type', 'radio');
    inputElement.setAttribute('name', elt_name);
    inputElement.setAttribute("value", elt_value);
    var func = new Function("alert(this.value + ' is selected!')");
    inputElement.onclick = func;

    if (is_selected) {
        inputElement.setAttribute("checked", "checked");
    }

    var divElement = document.getElementById("container");
    divElement.appendChild(inputElement);
    divElement.appendChild(document.createTextNode(elt_label));
    divElement.appendChild(document.createElement("br"));
}

This works perfectly in Firefox. but in Internet Explorer the radio buttons can’t be selected. After googling the internet, I find a solution which works well in IE:

var inputElement = document.createElement(’<input type=”radio” name=”‘ + elt_name + ‘” />’);

However, another problem arises. IE leaves the radio button unchecked even I set the checked status in my javascirpt like this:

inputElement.setAttribute(”checked”, “checked”);

It seems that this has no side-effect on the behavior of IE before I insert the radio button into the DOM. So I move the code used to set the checked attribute down to after the statement used to insert the radio button into the document, it works fine.

The following is the full source code:

<html>
<head>
<title>create radio button</title>
<script type="text/javascript">
function createRadioButton(elt_name, elt_value, elt_label, is_selected) {
    var inputElement;
    try{
        inputElement = document.createElement('<input type="radio" name="' + elt_name + '" />');
    }catch(err){
        inputElement = document.createElement('input');
        inputElement.setAttribute('type', 'radio');
        inputElement.setAttribute('name', elt_name);
    }
    inputElement.setAttribute("value", elt_value);
    var func = new Function("alert(this.value + ' is selected!')");
    inputElement.onclick = func;

    var divElement = document.getElementById("container");
    divElement.appendChild(inputElement);
    divElement.appendChild(document.createTextNode(elt_label));
    divElement.appendChild(document.createElement("br"));

    if (is_selected) {
        inputElement.setAttribute("checked", "checked");
    }
}
function testFunc() {
   var divElement = document.getElementById("container");

   // empty object of its children
   var len = divElement.childNodes.length;
   for (var i = 0; i < len; i++) {
       divElement.removeChild(divElement.childNodes[0]);
   }

   // alternate method
   /*
   while(divElement.hasChildNodes() == true) {
      divElement.removeChild(divElement.childNodes[0]);
   }
   */

   createRadioButton('sex', 'm', 'male', true);
   createRadioButton('sex', 'f', 'female', false);
}
</script>
</head>
<body>
<h1>Create radio button dynamically</h1>
<div id="container"></div>
<input type="button" value="Create" onclick="testFunc()" />
</body>

Krugle - a search engine for source code and code-related information

Written by coregps on Thursday, September 21st, 2006 in General.

Krugle makes it easy for developers to find source code and technical information by using its simple, friendly, ajax-enabled interface. It also lets developers add their own comments to entire code files or specific lines of code, allowing for useful code-centric communication between developers.

For more information about Krugle, please visit http://www.krugle.com/.

In-Place editing with script.aculo.us in JSP

Written by coregps on Monday, September 18th, 2006 in Java, AJAX.

Ajax makes it possible to refresh defined parts of the user interface without refreshing the whole web page. An responsive Ajax enabled web site can attract more customers and get more business. With the goodness of Ajax, I implement the in-place editing function in my recent e-commerce web application. Our customers can update the quantity of item(s) in the shopping cart without seeing the blank web page.

The in-place editing function can be implemented by using the Script.aculo.us In Place Editor easily. For those new to Script.aculo.us, it is an add-on to the Prototype framework, which provides easy-to-use, cross-browser user interface JavaScript libraries to create rich interface web sites and web applications. The current version of script.aculo.us is 1.6.4. It can be download at http://script.aculo.us/downloads.

The constructor of Ajax.InPlaceEditor takes three parameters. The first is the element that should support in-place editing. The second is the url to submit the changed value to. The server should respond with the updated value (the server might have post-processed it or validation might have prevented it from changing). The third is a hash of options.

new Ajax.InPlaceEditor( element, url, [options]);

Supported options are (all are optional and have sensible defaults):

Option since default Description
okButton V1.6 ?true? If a submit button is shown in edit mode (true,false)
okText V1.5 ?ok? The text of the submit button that submits the changed value to the server
cancelLink V1.6 ?true? If a cancel link is shown in edit mode (true,false)
cancelText V1.5 ?cancel? The text of the link that cancels editing
savingText V1.5 ?Saving?? The text shown while the text is sent to the server
clickToEditText V1.6 ?Click to edit? The text shown during mouseover the editable text
formId V1.5 id of the element to edit plus ?InPlaceForm? The id given to the

element
externalControl V1.5 null ID of an element that acts as an external control used to enter edit mode. The external control will be hidden when entering edit mode and shown again when leaving edit mode.
rows V1.5 1 The row height of the input field (anything greater than 1 uses a multiline textarea for input)
onComplete V1.6 ?function(transport, element) {new Effect.Highlight(element, {startcolor: this.options.highlightcolor});}? Code run if update successful with server
onFailure V1.6 ?function(transport) {alert(?Error communicating with the server: ? + transport.responseText.stripTags());}? Code run if update failed with server
cols V1.5 none The number of columns the text area should span (works for both single line or multi line)
size V1.5 none Synonym for ?cols? when using single-line (rows=1) input
highlightcolor ? Ajax.InPlaceEditor.defaultHighlightColor The highlight color
highlightendcolor ? ?#FFFFFF? The color which the highlight fades to
savingClassName V1.5 ?inplaceeditor-saving? CSS class added to the element while displaying ?Saving?? (removed when server responds)
formClass Name? V1.5 ?inplaceeditor-form? CSS class used for the in place edit form
hoverClass Name? ? ?
loadTextURL V1.5 null Will cause the text to be loaded from the server (useful if your text is actually textile and formatted on the server)
loadingText V1.5 ?Loading?? If the loadText URL option is specified then this text is displayed while the text is being loaded from the server
callback V1.5 function(form) {Form.serialize(form)} A function that will get executed just before the request is sent to the server, should return the parameters to be sent in the URL. Will get two parameters, the entire form and the value of the text control.
submitOnBlur V1.6 ?false? This option if true will submit the in_place_edit form when the input tag loses focus.
ajaxOptions V1.5 {} Options specified to all AJAX calls (loading and saving text), these options are passed through to the prototype AJAX classes.

You can visit http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor for more information.

To implement the in-place editing in JSP, follow the steps below:

1. Download the latest version of script.aculo.us at http://script.aculo.us/downloads, unzip the archive file and put all javascript files in a directory of your web application (I put them in js directory), and then add the following two lines to the <head> tag:

<script src=”javascripts/prototype.js” type=”text/javascript”></script>
<script src=”javascripts/scriptaculous.js” type=”text/javascript”></script>

2. Implement the in place editor in JSP page.

<c:forEach var="item" items="${sessionScope.cart.items}" varStatus="status">
  <c:set var="product" value="${item.item}" />
  <tr id="row${product.products_id}">
    <td><a href="productdetail.jsp?products_id=${product.products_id}">${product.products_name}</a></td>
    <td><fmt:formatNumber type="currency" value="${product.products_final_price}" /></td>
    <td><span id=”quant${product.products_id}”>${item.quantity}</span><a id=”edt${product.products_id}” href=”#”> Edit</a></td>
    <td id=”total${product.products_id}_${product.products_attributes_pair}_${product.bundled_flag}”><fmt:formatNumber type=”currency” value=”${item.quantity * product.products_final_price}” /></td>
    <td><input type=”checkbox” id=”delcartitem” name=”delcartitem” value=”${product.products_id}” /></td>
  </tr>
  <script>
    new Ajax.InPlaceEditor($(’quant${product.products_id}’), ‘CartServlet’, {
        okText:’Save’,cancelText:’Cancel’, savingText:’Updating…’,
        size:5, externalControl: ‘edt${product.products_id}’,
        callback: function(form, value) { return ‘action=Update&pid=${product.products_id}&newqty=’ + escape(value) },
        onFailure: function(t) { ajax_error(t) },
        onComplete: function(t) { ajax_success(t, ‘${product.products_id}’) },
        ajaxOptions: {method: ‘get’}
    });
  </script>
</c:forEach>

function ajax_success(transport, element) {
    var items = transport.getResponseHeader(”items”);
    var total = transport.getResponseHeader(”total”);
    var subtotal = transport.getResponseHeader(”subtotal”);
    var remove = transport.getResponseHeader(”remove”);
    // refresh cart items using AJAX
    refreshdata(items, subtotal, remove);
}
function ajax_error(transport) {
    if (transport.status == 500) {
        var errorStatus = transport.statusText;
        if (errorStatus == “EMPTY_ERROR”) {
            alert(”Quantity can not be empty!”);
        } else if (errorStatus == “FORMAT_ERROR”) {
            alert(”Quantity is an invlidate number!”);
        }
    }
}

3. Implement the server side component. The following code snippet is used to modify the quantity of item(s) in the shopping cart.

String action = Browser.getString(request, "action");
if (action.equalsIgnoreCase("Update")) {
    HttpSession session = request.getSession();
    ShoppingCart cart = (ShoppingCart) session.getAttribute("cart");

    String productId = Browser.getString(request, "pid");
    String qty = Browser.getString(request, "newqty");
    response.setContentType("text/xml; charset=UTF-8");
    response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
    response.setHeader("Pragma","no-cache"); //HTTP 1.0
    response.setDateHeader("Expires", 0); //prevents caching at the proxy server
    if (qty.equals("")) {
        response.sendError(response.SC_INTERNAL_SERVER_ERROR, "EMPTY_ERROR");
    } else {
        try {
            int newQty = Integer.parseInt(qty);
            Map map = cart.update(productId, newQty);
            if (map != null) {
                response.setHeader("items", Integer.toString(cart.getNumberOfItems()));
                response.setHeader("total", map.get("total").toString());
                response.setHeader("subtotal", map.get("subtotal").toString());
                response.setHeader("remove", map.get("remove").toString());
            }
            response.getWriter().print(newQty);
        } catch (Exception e) {
            response.sendError(response.SC_INTERNAL_SERVER_ERROR, "FORMAT_ERROR");
        }
    }
}

That’s all. Two things should be noted:

1. The form data should be sent encoded in UTF-8.

2. The method setHeader must be called before sendError.

You can visit script.aculo.us for more information.

getElementById has no properties in Firefox

Written by coregps on Wednesday, September 6th, 2006 in AJAX, Web Design.

I have a register JSP page that contains a form with some input fields. I use the getElementById method to retrieve form values and post them through AJAX. It works very well in IE. But in Firefox, I get the following error:

document.getElementById(”customers_name”) has no properties

I reviewed the W3C’s DOM specification carefully, and found the getElementById section.

getElementById introduced in DOM Level 2
Returns the Element that has an ID attribute with the given value. If no such element exists, this returns null.

I checked my code again and found that one of the input elements has no ID attribute. It is something like this:

<input type=”text” name=”customers_name” size=”30″ />

When I assigned an ID attribute to the element, it works fine.

<input type=”text” id=”customers_name” name=”customers_name” size=”30″ />

It appears that IE does not implement the DOM 2 Core and DOM 3 Core specifications correctly. It grabs form values based on the NAME attribute. While Firefox finds form elements by ID, when the input has no ID, null is returned. So, Firefox do the right thing.

Loading configuration files under WEB-INF/classes

Written by coregps on Tuesday, September 5th, 2006 in Java.

We often need to load configuration files under WEB-INF/classes directory, it is usually a properties file or an XML file. There are many different ways of doing this. The method below can be used only in a non-static method.

public File getResource(String fileName) {
    URL url = this.getClass().getResource("/" + fileName);
    return url != null ? new File(url.getFile()): null;
}

When called in a static method, an error will occur:

non-static method XXX cannot be referenced from a static context

To find the absolute path of a file under WEB-INF/classes in a static method, I often use the following two solutions:

public static File getFileFromInputStream(String fileName) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    URL url = cl.getResource(fileName);
    if (url != null) {
        File file = new File(url.getFile());
        return file;
    } else {
        return null;
    }
}

or

public class MailService {
    ……

    public static File getResource(String fileName) {
        URL url = MailService.class.getResource(”/” + fileName);
        return url != null ? new File(url.getFile()): null;
    }

    ……
}

Replacing line feeds with HTML breaks using JSTL

Written by coregps on Monday, September 4th, 2006 in Java.

In my recent e-commerce web application, I use a textarea input element to gather reviews from our customers and store them in a database. The text user entered may contain line breaks (\n). When I retrieve the data and display it in a web page - the line breaks are ignored, and the result is pretty unreadable.


I first tried to replace these line breaks (\n) with html breaks (<br>) by using the following statement:


${fn:replace(reviewDB.review_text, “\n”, “<br />”)}

However, I got the following exception:


/productdetail.jsp(268,14) “${fn:replace(reviewDB.review_text, “\n”, “<br />”)}” contains invalid expression(s): javax.servlet.jsp.el.ELException: Encountered “”\n”, expected one of [<INTEGER_LITERAL>, <FLOATING_POINT_LITERAL>, <STRING_LITERAL>, “true”, “false”, “null”, “(”, “-”, “not”, “!”, “empty”, <IDENTIFIER>]

Finally, I found two solutions to achieve this work, the following is the first solution:


<%pageContext.setAttribute(”linefeed”, “\n”); %> <c:out value=”${fn:replace(review.reviews_text, linefeed, “<br />”)}” escapeXml=”false”/>

Another solution is using the Jakarta String Tag Library http://jakarta.apache.org/site/downloads/downloads_taglibs-string.cgi.


<%@ taglib uri=”http://jakarta.apache.org/taglibs/string-1.1″ prefix=”str” %> <str:replace replace=”NL” with=”<br />” newlineToken=”NL”>${review.reviews_text}</str:replace>

Note that this solution also requires Commons Lang library, which can be downloaded at http://jakarta.apache.org/site/downloads/downloads_commons-lang.cgi



Site Navigation