Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: indentation

...

Code Block
languagexml
title/ajax/index.jsp
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %> 
<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
<head> 
<title>My First Ajax Stripe</title> 
<script type="text/javascript" 
src="${pageContext.request.contextPath}/ajax/prototype.js"></script> 
<script type="text/javascript" xml:space="preserve"> 
    /* 
    * Function that uses Prototype to invoke an action of a form. Slurps the values 
    * from the form using prototype's 'Form.serialize()' method, and then submits 
    * them to the server using prototype's 'Ajax.Updater' which transmits the request 
    * and then renders the response text into the named container.
    * 
    * NOTE: Requires Prototype version 1.6 or above. 
    * 
    * @param form reference to the form object being submitted 
    * @param event the name of the event to be triggered, or null 
    * @param container the name of the HTML container to insert the result into 
    */ 
    function invoke(form, event, container) { 
        if (!form.onsubmit) { form.onsubmit = function() { return false } }; 
 var params = Form     var params = Form.serialize(form, {submit:event}); 
        new Ajax.Updater(container, form.action, {method:'post', parameters:params}); 
    } 
</script> 
</head> 
<body> 
<h1>Stripes Ajax Calculator</h1> 

<p>Hi, I'm the Stripes Calculator. I can only do addition. Maybe, some day, a nice programmer 
will come along and teach me how to do other things?</p> 

<stripes:form action="/examples/ajax/Calculator.action"> 
    <table> 
        <tr> 
            <td>Number 1:</td> 
            <td><stripes:text name="numberOne"/></td> 
 </tr>  <tr>  <td>Number    </tr> 
        <tr> 
            <td>Number 2:</td> 
            <td><stripes:text name="numberTwo"/></td> 
        </tr> 
        <tr> 
            <td colspan="2"> 
                <stripes:submit name="add" value="Add" 
                    onclick="invoke(this.form, this.name, 'result');"/>> 
                <stripes:submit name="divide" value="Divide" 
                    onclick="invoke(this.form, this.name, 'result');"/> 
            </td> 
</tr> 
<tr> 
        </tr> 
        <tr> 
            <td>Result:</td> 
            <td id="result"></td> 
        </tr> 
    </table> 
</stripes:form> 
</body> 
</html> 

...

Code Block
xml
xml
 
<stripes:submit name="add" value="Add" 
    onclick="invoke(this.form, this.name, 'result');"/> 
<stripes:submit name="divide" value="Divide" 
    onclick="invoke(this.form, this.name, 'result');"/> 

Here we see submit buttons that trigger a javascript function when they are clicked, and pass it the form, the name of the button that was clicked (as the Stripes event name) and the name of the HTML element into which to insert the result. Lastly we see:

Code Block
xml
xml
 
<script
    type="text/javascript" 
    src="${pageContext.request.contextPath}/ajax/prototype.js"></script> 
<script type="text/javascript" xml:space="preserve"> 
    /* ... */ 
    function invoke(form, event, event, container) { container) { 
        if (!form.onsubmit) { form.onsubmit = function() { return false } }; 
        var params = Form.serialize(form, {submit:event}); 
        new Ajax.Updater(container, form.action, {method:'post', parameters:params}); 
    } 
</script> 

The first script tag imports the Prototype JavaScript library. The second block defines a little utility function that uses Prototype to invoke an ActionBean on the server and update the contents of an HTML container when the server delivers the result. Before making the call to the server, it disables the normal form submission process by setting up the form's "onsubmit" event handler to return false.

...

Code Block
title"AJAX CalculatorActionBean.java"
 
package net.sourceforge.stripes.examples.ajax; 

import net.sourceforge.stripes.action.ActionBean; 
import net.sourceforge.stripes.action.ActionBeanContext; 
import net.sourceforge.stripes.action.DefaultHandler; 
import net.sourceforge.stripes.action.Resolution; 
import net.sourceforge.stripes.action.StreamingResolution; 
import net.sourceforge.stripes.validation.Validate; 
import net.sourceforge.stripes.validation.ValidationError; 
import net.sourceforge.stripes.validation.ValidationErrorHandler; 
import net.sourceforge.stripes.validation.ValidationErrors; 

import java.io.StringReader; 
import java.util.List; 

/** 
* A very simple calculator action that is designed to work with an ajax front end. 
* @author Tim Fennell 
*/ 
public class CalculatorActionBean implements ActionBean, ValidationErrorHandler { 
    private ActionBeanContext context; 
    @Validate(required=true) private double numberOne; 
    @Validate(required=true) private double numberTwo; 

    public ActionBeanContext getContext() { return context; } 
    public void setContext(ActionBeanContext context) { this.context = context; } 

    @DefaultHandler public Resolution add() { 
        String result = String.valueOf(numberOne + numberTwo); 
        return new StreamingResolution("text", new StringReader(result)); 
    } 

    public Resolution divide() { 
        String result = String.valueOf(numberOne / numberTwo); 
        return new StreamingResolution("text", new StringReader(result)); 
    } 

    // Standard getter and setter methods 
    public double getNumberOne() { return numberOne; } 
    public void setNumberOne(double numberOne) { this.numberOne = numberOne; } 

    public double getNumberTwo() { return numberTwo; } 
    public void setNumberTwo(double numberTwo) { this.numberTwo = numberTwo; } 
} 

...

Code Block
 
@DefaultHandler 
public Resolution add() { 
    String result = String.valueOf(numberOne + numberTwo); 
    return new StreamingResolution("text", new StringReader(result)); 
} 

...

Code Block
 
public class CalculatorActionBean implements ActionBean, ValidationErrorHandler { 
    .... 
    /** Converts errors to HTML and streams them back to the browser. */ 
    public Resolution handleValidationErrors(ValidationErrors errors) throws Exception { 
        StringBuilder message = new StringBuilder(); 

        for (List<ValidationError> fieldErrors : errors.values()) { 
            for (ValidationError error : fieldErrors) { 
                message.append("<div class=\"error\">");">"); 
                message.append(error.getMessage(getContext().getLocale())); 
                message.append("</div>"); 
            } 
        } 

        return new StreamingResolution("text/html", new StringReader(message.toString())); 
    } 
    ... 
} 

Because the ActionBean implements ValidationErrorHandler Stripes will invoke the handleValidationErrors method if any validation errors are generated. In this case the method loops through the set of errors constructing an HTML fragment with each error in a separate div. This is then returned to the client, again using the StreamingResolution. Now when validation errors occur they are displayed in the same place that the result would be displayed.

...

Code Block
titleUsing an anonymous Resolution
 
@HandlesEvent("GetLotsOfData") 
public Resolution getLotsOfData() { 
  {  Map<String,String> items = getReallyBigMap(); 
    return new Resolution() { 
        public void execute(HttpServletRequest request, HttpServletResponse response) throws Exception { 
            response.setContentType("text/xml"); 

            response.getOutputStream().print("<entries>"); 
            for (Map.Entry<String,String> entry : items.entries()) { 
                response.getOutputStream().print("<entry><key>"); 
                response.getOutputStream().print(entry.getKey()); 
                response.getOutputStream().print("</key><value>"); 
                response.getOutputStream().print(entry.getValue());getValue()); 
                response.getOutputStream().print("</value></entry>"); 
            } 
            response.getOutputStream().print("</entries>"); 
        } 
    } 
} 

Using ForwardResolution to return html fragments

...

Code Block
 
public Resolution showScientificCalc() { 
    return new ForwardResolution("/fictitious/scientificCalcControls.jsp"); 
} 

...

Code Block
titleHandling a JavaScriptResolution
 
/** Function that handles the update when the async request returns. */ 
function update(xhr) { 
    var output = eval(xhr.responseText); 
    $('result').innerHtml = output; 
} 

/** Function to submit a request and invoke a handler when it completes. */ 
function invoke(form, event, handler) { 
    var params = Form.serialize(form, {submit:event}); 
    new Ajax.Request(form.action, {method:'post', parameters:params, onSuccess:handler}}); 
}