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