Illustrated Guide on Woodstock Client-Side Library

Abstract

The Woodstock Client-Side Library provides a rich set of Web-based components. These components can be used client-side, independent of server implementation. This document provides basic concepts of working with the Woodstock client-side library. A few major use cases are presented, analyzed and implemented. Based on the specified use cases, the demo application has been created to show usage patterns of the Woodstock client-side library and replaceable server implementation ( plain Java servlets and PHP back-end demonstrated). Documented source code and NetBeans projects can be found in “Download Source” section of this document.



Download Source

Netbeans 6.1 project – ZIP format
Note that none of the library files ( json2.jar, mysql-connector.jar, woodstock library) are present in the archive and must be downloaded and installed separately.


This document post is truncated. For a full version of the document - see web\\design\\index.html in the downloaded archive

Overview

Developer's Responsibilities .When using the Woodstock client-side library, the developer provides the following code

  • code to instantiate widgets

  • code for business logic ( both server side and , if needed, client-side). Components' data and interfaces are concise and clearly defined, and any server implementation can be plugged.

  • (optionally) code for transport. Widgets data can be transferred with any means of transport that the browser supports. Typically HTTP is used, but any other protocol can be used. By default, data can be submitted through regular page submit or with an Ajax call. Woodstock provides the default implementation of Ajax transport, in addition this particular demo provides a couple of examples. Also, other libraries can be used for transport. For example, the demo has been tested with YahooUI(tm) Ajax connection code.

Application Design Approach. There are many ways in which web application can be designed, the most popular being:

  • Traditional web applications present all data on the page, and upon submission all successful form elements are submitted in the post.

  • Ajax introduces the ability to submit only selective data, without page submit or update.

  • JavaScript adds further power to introduce programming elements on the client( browser).

Woodstock components support all of the above approaches. Components represent regular HTML elements ( combined in creative ways), which can be successfully submitted on page submit. Components' data can also be used in Ajax transactions. Most components have embedded Ajax functionality that handles data submission 'automatically'. Also,extensive JavaScript logic is attached to every component – each component can be introspected for the state of its view and data, controlled, and can participate in the client-side event mechanism.

The demo represents a web application with the implementation of all elements above. Application design has a one-page concept, where all actions take place through the Ajax calls, and without page change, update or forward. Use Case “Build database backed-up address book with full set of CRUD operations” contains a high level description of interactions within the demo application.

Note that the design presented here reflects a particular choice of demo creator. The developer chooses how to to design application.








Basic Elements of Woodstock Application.

Woodstock client-side library is a JavaScript library. It is provided in the archive and also available as a NetBeans module. Archive contains:

    • JavaScript code

    • Theme resources ( images, CSS)

    • Localization resources

The demo adds the following code:

    • Client-side business logic

    • Ajax connection code (Note: Default XHR ( Ajax) implementation has been added to the Woodstock library since the time demo application has been written. This implementation can be used instead of attached connection.)

    • Server side business logic

Visual Log. The essence of programming with Woodstock widgets is to instantiate them on the page, to be able to retrieve or set widgets data, and if needed pass this data to the server for control or business decisions. In order to illustrate data on which demo application and its widgets operate, demo application offers 'visual log' accessible by pressing 'Show Log” button. Such log shows what data is sent to the server, and received back in response to the Ajax calls. Note that similar data can be obtained by using a Firebug Net XHR monitor (http://www.getfirebug.com/) which is highly recommended as an environment for debugging of any web application.

The following is an example of log output on the page for email verification, where Ajax call is used to transfer data:




Skills required: In general, the following skills are anticipated for advanced use of Woodstock components: HTML, JavaScript, and if server logic is introduced into the application – server language of choice. Demo presented uses Java for server language.

Terms. Note that terms component and widget are used interchangeably throughout the document.



Deployment and Participants

The following is the deployment diagram of the demo that we use in this guide. In general this reflects typical web application design:




Notes to the “Deployment diagram”:

  1. Only few components used in the demo are shown in Woodstock library

  2. Packages are shown where they are running, as oppose to where the source location is. Specifically, initial location of all packages in typical Web application is on the server.

  3. Demo package is intentionally pictured isolated from Woodstock library in order to provide the boundaries of developer's domain of work. In real application, everything in “Demo package” is (currently) considered developer's responsibility.

  4. In addition to the built-in support for XHR transactions, the demo provides 2 versions of Ajax connection example – connection.js and connection-simple.js, both exposing the same major interface. Connection-simple.js is a simple implementation of Ajax call, without the sophistication of handling error messages, timeouts, etc. Connection.js is a robust full-featured implementation that handles all of the details of multi-browser support and error conditions; it also handles form submission through the Ajax call. It is built based on YahooUI connection implementation, and provided as an example only. By default, demo application is configured to use connection.js:

    <script type="text/JavaScript" src="/proto/js/connection.js"></script>



The following participants(actors) play in the demo:


Notes to the “Actors diagram”:

  1. HTML page is used to create a view. It

    1. loads script files and theme artifacts

    2. instantiates widget

  2. Controller and Connector are JavaScript elements that perform client-side business logic and communication to the server, respectively. Note that controller can contain several JavaScript files/objects – they are combined into a single actor for simplicity.

  3. Data can be stored in any format, such as database, or plain data objects.



Application Dependencies

  • Basic Woodstock library is self-contained – it does not rely on any external libraries.

  • When optional JSFX extension of Woodstock library is used, it requires jsfx library to be available. This is required only to establish connection to JSF back end :

  • Demo application uses JSON to pass data between client and server and as such introduces the use of JSON libraries from http://json.org in JavaScript on the client and Java on the server.

One of the common uses of Woodstock library is to expand its archive into the web application. Thus all the resources ( JavaScript, theme, localization) become instantly available for HTTP loading. Alternative approaches are also available – for example ThemeService servlet can service the same resources from an archive, etc.

Use Cases

The following is the list of use cases targeted with this demonstration. The list is not intended to be exhaustive, but instead is meant to be seen as a starting set.

Use case descriptions are followed with the implementation instructions on the example of attached demo application.




Use Case 1: Instantiate client-side widget from plain HTML markup

Use Case

Summary: Instantiate widgets on the page with the direct use of JavaScript API.

Actors: View ( HTML page), Woodstock library

Prereq:

  1. Woodstock library deployed into web application

  2. Woodstock library is accessible through HTTP (expanded or archived)

Main Success Scenario:

    1. Specify Woodstock configuration

    2. Load Woodstock library scripts

    3. Load theme

    4. Load business logic scripts

    5. Instantiate widget(s)

Alternative Scenario Extensions:

    • none

Notes and Questions

    • none



Implementation

Example: addressbook.HTML. In this example application is deployed as web-context /proto

    Specify Woodstock configuration


Woodstock supports few configuration parameters that can be changed by the developer. Depending on configuration, different parts of library can be loaded – i.e. compressed vs. uncompressed JavaScript ( isDebug flag), support for JSFX ( webuiJsfx flag), etc.


All of the parameters have defaults, and do not need to be always specified. Thus minimally no configuration needs to be specified.



Options:

  1. Specify NO configuration –in this case you will inherit all of the default values. See configuration documentation (TODO) for description

  2. Specify the configuration. This can be required, for example, if JavaScript, is to be debugged, if you are changing the default locale, or if you are loading Jsfx support, etc.

    The following is the example of complete configuration parameters set.

 <script type="text/JavaScript">var woodstock4_3Config={
        "namespace":"woodstock",
        "webuiAll": true,
        "parseOnLoad": true,
        "theme": {"locale": "en-us"},
        "isStyleSheet": true,
        "isDebug": true,
        "webuiJsfx": false,
        "ajax": {"isJsfx": false}
    };
    </script>

Only partial configuration parameters that are not to take on default values need be supplied. Thus one can simply supply:


<script type="text/JavaScript">var woodstock4_3Config={
   "namespace":"woodstock"
   };
</script>

The namespace  parameter defines the namespace for woodstock libraries to be instantiated in. Once the namespace is defined as above, all of the Woodstock functions can be called with prefix woodstock. This is useful in order not to change the code on the page after upgrading from one version to another:


woodstock.widget.common.createWidget(locationId, properties)

If namespace is not set, all of Woodstock library functions are residing in the name space versioned by the release number, such as woodstock4_3. This can be useful if you want to load multiple version of Woodstock library on the same page, as it happens in a portal environment, for example both woodstock4_2 and woodstock4_3:


woodstock4_2.widget.common.createWidget(locationId, properties)
woodstock4_3.widget.common.createWidget(locationId, properties)

For this demo application, we assume that namespace:”woodstock” has been set and all functionality resides in the woodstock namespace.


    Load Woodstock library script

<script type="text/JavaScript" src="/proto/woodstock4_3_dev/suntheme/JavaScript_uncompressed/bootstrap.js"></script>

Note that in this example Woodstock library has been expanded into web application under ./woodstock4_3dev tree


    Load theme

    Theme is loaded as part of the bootstrap process in the previous example.


    Load business logic scripts

    The scripts to be loaded are developer's code as well as required libraries (if any) . For the demo, the following files are loaded:

<script type="text/JavaScript" src="/proto/js/lib/json2.js"></script> 
<script type="text/JavaScript" src="/proto/js/connection.js"></script> 
<script type="text/JavaScript" src="/proto/js/controller.js"></script> 


where json2.js is an implementation of JSON from http://json.org used in the demo, connection.js is an implementation of Ajax connection and controller.js contains helper methods to post requests to the server and process responses.


    Instantiate widget(s)

    Instantiation of the widget takes 2 steps: creation of the DOM element to hold the widget, and invoking the JavaScript method to create the widget itself. All widget instantiations look the same, with the exception of parameters. Interface looks like:

woodstock.widget.common.createWidget(locationId, properties)

    where

      • locationId is the identifier of an HTML element on the page at which the widget will render its own HTML. Such location is usually a DOM element specifically created to hold the widget – for example <span>.

      • properties is a JSON object specific to a particular widget. Documentation for Woodstock client-side library ( TODO reference) contains a detailed description of all widget names and properties. In particular, widget type ( 'button','alert', 'textfield', etc.) is defined as part of the properties.

    Important to note that that widget must be created at a location with unique id, and the widget itself must have a uniqueID. Thus locationId and the id of the created widget must be unique on the page. Also note that use of ':' as a delimeter within copmlex ids ( as presented in this paper – such as “form1:alert”) should be avoided in favor of “_”.

    Example below ( from addressbook.HTML) uses HTML markup to create an initially hidden alert widget.

<span id="spanAlert" >
<script type="text/JavaScript">
  woodstock.widget.common.createWidget(
    'spanAlert',{ // span id where widget is created 
    "widgetType":"alert", // name/type of the widget 
    "type":"information", // alert specific properties...
    "detail":"",
    "visible":false,
    "id":"form1:alert"}); //id of newly created widget 
</script>
</span>

As with all properties in Woodstock, one can provide only the minimum required, and rely on defaults for others. The same alert widget could be created like this:

<span id="spanAlert" >
<script type="text/JavaScript">
  woodstock.widget.common.createWidget(
    'spanAlert',{ // span id where widget is created 
    "widgetType":"alert", // name/type of the widget 
    "id":"form1:alert"}); //id of newly created widget 
</script>
</span>

    The next example ( from addressbook.HTML) uses HTML markup to create an action button that will call JavaScript method loadTable() upon onClick()..

<span id='loadButton'>
  <script type='text/JavaScript'>
    woodstock.widget.common.createWidget(
      'loadButton',{
          'primary':false,
          'widgetType':'button',
          'value':'Load Address Book',
          'title':'load',
          'mini':false,
          'id':'form1:loadButton',
          'onClick': 'loadTable(); return false;'
        });
   </script>
</span> 

NetBeans Woodstock Snippets plugin

Code snippets ( see snapshot on the right side) can be easily generated using NetBeans Woodstock plugin. You can drag and drop widgets from the palette into the source ( such as HTML, JSP, etc.), and the required code snippet will be generated. Unique IDs will also be generated automatically.




See the plugin documentation for more details (TODO reference)

<< Back to the List of Use Cases




Use Case 2: Retrieve and set widget data on the client-side

Use Case

Summary: Retrieve widget data on the client-side, with the goal to operate on it. Optionally submit data to the server.

Actors: Controller (application business logic), widget

Prereq:

  1. Loaded Woodstock library ( see Use Case “Instantiate client-side widget from plain HTML markup”)

  2. Loaded Widget ( see Use Case “Instantiate client-side widget from plain HTML markup”)

Main Success Scenario:

  1. Obtain reference to the widget

  2. Retrieve widget property set

  3. (optional) Retrieve individual property from property set.

  4. (optional) Set individual property from property set.

Alternative Scenario Extensions:

    • Widget data is automatically submitted/posted by the browser with the page submit. In case of page submit, only successful form elements are submitted. Usually this represents a smaller portion of widget data, although sufficient for most cases. In order to maintain this functionality, widget must be enclosed within a form

    • See Use Case “Submit and update widget data using Ajax ” for submission data to the server

Notes and Questions

    • For direct data retrieval purposes widget can be either hidden or visible on the page.

Implementation




Obtain reference to the widget

Use woodstock.widget.common.getWidget(id) to obtain reference to the widget

for example, in order to retrieve alert we created in Use Case “Instantiate client-side widget from plain HTML markup”:

var widgetId = “form1:alert”;
var widget = woodstock.widget.common.getWidget(widgetId);
if (!widget) {
    logError("Widget " + widgetId + " not found");
    return false;
}

Alternatively, one can retrieve widgets top-most DOM element. When widget is created, it makes all of its public functions available on the top-most DOM element of widget structure. This element will have the same ID as widget has ( i.e. used during the instantiation with createWidget). Thus, instead of woodstock.widget.common.getWidget(widgetId); the following can be used :

var widgetId = “form1:alert”;
var widget = document.getElementById(widgetId);
if (!widget) {
   .....
}

The difference between obtaining a widget reference ( with getWidget), as oppose to a top-most DOM element ( with document.getElementById) is that only public widget methods are exposed at the top-most DOM element.



Retrieve widget property set

widget.getProps() returns map of widget properties

(optional) Retrieve individual property from property set.

All widgets share common properties, such as id, visible, etc., as well as have a set of properties specific to a particular widget type ( see documentation). The following displays the type of the alert widget :

alert(widget.getProps().type);

(optional) Set individual property from property set.

In exactly the same way, the property can be set. Setting properties can affect widget visual presentation ( size, position, style) or the data it presents ( text in textfield, rows and columns in table, etc) The following changes the type of the alert widget into error:

widget.setProps({type :'error'});

Multiple properties can be set at once. For example, provided that alert widget has been created on the page as in Use Case “Instantiate client-side widget from plain HTML markup”, and widget is a reference wo alert widget, the following displays error alert. If widget was hidden, it will be visible upon completion of the call:





widget.setProps({type :'error', visible: true, 'message' : 'Email address ...'});




<< Back to the List of Use Cases




Use Case 3: Submit and update widget data using Ajax

Use Case

Summary: Submit widget data (obtained in Use Case 2) to the server using Ajax call, and without page update. Process request on the server and provide a response. Change widget view based on the server response.

Actors: Controller (application business logic), widget, connector, server controller ( application business logic),

Prereq:

  1. Loaded Woodstock library ( see Use Case “Instantiate client-side widget from plain HTML markup”)

  2. Loaded Widget ( see Use Case “Instantiate client-side widget from plain HTML markup”)

  3. Retrieved widget data ( see Use Case “Retrieve and set widget data on the client-side”)

Main Success Scenario:

  1. Client: Prepare data for posting

  2. Client: Post data with the Ajax call

  3. Server: parse Ajax request

  4. Server: perform business logic

  5. Server: write Ajax response

  6. Client: parse response

  7. Client: update widget

Alternative Scenario Extensions:

Notes and Questions

    • none

Implementation

The example implementation provides “service” to verify email address before contact is added to the address book. See testEmail() function in addressbook.HTML. Controller retrieves email address from the textField widget ( textField value), encodes the string and posts the Ajax transactions. On the server, a servlet ( addressbook/AddressBookServlet.java) parses request, checks whether specified email address is presented in format name@host ( fake verification) and writes a message back to the client, specifying also the id of the destination widget. Message represents a JSON object containing alert properties. Destination id represents an id of a widget ( alert) on the client-side. On the client, alert properties are pushed into the alert widget, which causes alert to be shown with the message.

Note that textField component also has an autovalidate functionality that enables automatically validation of the field on onBlur event with the use of custom event subscriber. This approach is an alternative ( and likely more potent) implementation and is not used in this particular demonstration.




Client: Prepare data for posting

In this demo, data is posted as a set of key/value pairs of post request. The only rule that has to be observed is to encode data when posted. Controller maintains post which represents a string key1=value1&key2=value2&... and allows to incrementally add to the post with addToPost() method. Once key/value string is complete with all data, it can be posted.


The following, for example, creates a post string that contains only one pair: EXECUTE_testEmail=value. This parameter is meant to convey to the server: “Execute command testEmail on value of the parameter”. Again, the choice for syntax is totally up to the application developer.


//reset post string to empty string
controller.getPost(true);

//retrieve data to be posted
var email  = document.getElementById('form1:email').getProps().value;

//EXECUTE conveys a command to server
controller.addToPost("EXECUTE_" + "testEmail",email);


Client: Post data with the Ajax call

Data is posted through simple Ajax implementation connector.js. Currently Woodstock does not offer independent Ajax library, but demo includes one. Also, there are plenty of public libraries with Ajax post functionality, such as YahooUI. For examples of how to make an Ajax call, see AJAX:Getting Started


controller.postData(controller.getPost(), '/proto/AddressBookServlet'); // post string, URL


If you take a look at content of postData function, you will see that controller registers a callback functions ( to be called when call is returned, or failed) and calls connection.asyncRequest('POST', url, callback, postString);


Server: parse Ajax request

Ajax request comes in as regular POST or GET request. Thus existing technologies can be used to parse the request. Demo uses simple servlet to obtain request parameters, parse them, and based on anticipated format of request key/value pairs make business logic decisions





In the previous example, simple strings were used for value of the parameter. Thus it is sufficient just to retrieve the servlet HttpRequest parameter and take its value.


request.getParameter(name)

In more complicated cases, we will be passing stringified JSON object as value of the parameter. See Use Case “Submit multiple widgets to server in single Ajax call” for parsing more complex parameters.



Server: perform business logic

AddressBookServlet takes email name, checks if it contains '@'-sign, and renders message back to the client.


// -------- TEST EMAIL command
if (value.indexOf("@")>0) {
    message = "Email address " + value + " has been verified";
} else {
    message = "Email address " + value + " must have 'name@host' format";
    messageType = "error";
}

Generally, response can be rendered in arbitrary format. Demo uses JSON string to pass widget properties back to the client. JSON string can be easily parsed into JavaScript object.


Server: write Ajax response


First, create JSONObject for alert:


protected JSONObject renderMessage() throws JSONException {
//ALERT widget props
JSONObject alertProps = new JSONObject();
boolean visible = (message == null) ? false : true;
alertProps.put("visible", visible);
alertProps.put("summary", message);

if (messageType != null) {
    alertProps.put("type", messageType);
} else {
    alertProps.put("type", "info");
}
return alertProps;
}


and finally dump out the content of the alert properties JSON to the response stream:


PrintWriter out =response.getWriter();
JSONObject responseJson = new JSONObject();
responseJson.put("form1:alert", renderMessage());
//write response
responseJson.write(out);



Thus, the response will contain exactly the following data:


{
    "form1:alert":{
      "summary":"Email address woodstock-dev@sun.com has been verified",
      "type":"info",
      "visible":true
    }
} 


which has the format

{
  widgetId1: widget1Properties,
  widgetId2: widget2Properties,
...
}, 

where widgetProperties is yet another JSONObject containing properties specific to the widget.



Client: parse response

When response comes back to the client, it is very easy to parse it into native JavaScript object format. Since is our demo we decided that we can potentially render multiple widgets data back, we parse the JSON object, iterate over potentially multiple all widget in it, and push properties onto respective widget ( see controller.js).



//parse the response
var propsMap = JSON.parse(o.responseText);
for (var widgetName in propsMap) {
    var props = propsMap[widgetName];
    var widget = woodstock.widget.common.getWidget(widgetName);
    if (!widget) {
        logError("Returned widget "+ widgetName +" is not found");
        return;
    }
    widget.setProps(props);
}


Client: update widget

Widget is updated as the result of setProps() call above. See Use Case ''Retrieve and set widget data on the client-side” for details on setProps().


<< Back to the List of Use Cases


Use Case 4: Prepare widget properties and update widget

Use Case

Summary: Provide data sufficient to change widget visual representation, state or behavior. Data can be provided purely client-side, or as the result of server activity.

Actors: Controller (application business logic), widget, Server Controller (application business logic), connection

Prereq:

  1. Loaded Woodstock library ( see Use Case “Instantiate client-side widget from plain HTML markup”)

  2. Loaded Widget ( see Use Case “Instantiate client-side widget from plain HTML markup”)

Main Success Scenario:

  1. Client: Obtain reference to the widget ( See Use Case “Retrieve widget data on the client-side”, Step 1)

  2. Server or Client: Prepare widget properties

  3. Client: Set Properties on the widget (See Use Case “Retrieve and set widget data on the client-side”)

Alternative Scenario Extensions:

    • If widget properties are prepared on the server, the following additional steps are to be taken:

      • Build widget data outside of JavaScript environment ( on the server)

      • Transport data from server to the client ( See Use Case “Submit widget data “ Step 4 and after)

Notes and Questions

    • none

Implementation

Bulk of the work to be done has already been discussed in previous use cases, and will not be repeated here. This use case primarily addresses how to correctly prepare data for the widget.

Server or Client: Prepare widget properties

Widgets are updated with the use of widget.setProps(propertyMap) method. PropertyMap parameter contains 0-N properties required for a particular widget, and is widget specific. As the result, widget state will be updated. Note that widget my have state that does or does not have visual presentation effect.

When widget is created, it creates certain structure of HTML DOM elements in the documents. Such DOM elements represent widget visually. Some properties will affect these DOM elements directly. For example, visible property will hide/show the top-most DOM element of the widget.


Other properties change logic of the widget. For example, they can change the polling interval with which progressBar publishes events for updated progress.


Widget documentation (TODO reference) contains description of all the properties. Only those properties passed with setProps will be updated, so it is safe to use partial set. For example, one can change the type of alert from whatever current type is to 'error' by:

alertWidget.setProps( { type: 'error'});


PropertyMap can be built on the client ( browser) in native JavaScript object format. The following example changes value of the text field, and makes it 'invalid':


var textFieldWidget = document.getElementById('form1:email');
var textFieldProps = {};
textFieldProps.value = 'new value';
textFieldProps.valid = false;

textFieldWidget.setProps(textFieldProps);


which will immediately change email field on the page from to



Again, the same can be accomplished with

textFieldWidget.setProps( {
    value:'new value',
    valid: false
);

Example of the property that would not change the visual presentation of the widget, but instead will update the logic:

textFieldWidget.setProps( {
    autoValidate:'true'
);

This example will put textField into autoValidate mode, where textField will generate validation event on onBlur()


For a more sophisticated example, the following will change the content of the table with 3 rows of data. Not only these properties will provide new table data, they also provide column layout and description. Note that as long as JSON format is observed, within each JSON object, the sequence of parameters supplied does not matter.


var tableProperties = {
        "rowGroups": [{
            "widgetType": "table2RowGroup",
            "rows": [[{
                "value": "false",
                "widgetType": "checkbox",
                "visible": true,
                "name": "check0",
                "id": "check0"
            },
            {
                "value": "Jules",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "0"
            },
            {
                "value": "Verne",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "1"
            },
            {
                "value": "jules.verne@earth.net",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "2"
            }], [{
                "value": "false",
                "widgetType": "checkbox",
                "visible": true,
                "name": "check1",
                "id": "check1"
            },
            {
                "value": "Herbert",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "10"
            },
            {
                "value": "Wells",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "11"
            },
            {
                "value": "herbert.wells@earth.net",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "12"
            }], [{
                "value": "false",
                "widgetType": "checkbox",
                "visible": true,
                "name": "check2",
                "id": "check2"
            },
            {
                "value": "John",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "20"
            },
            {
                "value": "Wyndham",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "21"
            },
            {
                "value": "john.wyndham@earth.net",
                "widgetType": "staticText",
                "visible": true,
                "escape": true,
                "id": "22"
            }]],
            "maxRows": 5,
            "page": 1,
            "visible": true,
            "first": 0,
            "totalRows": 3,
            "columns": [{
                "width": "20px",
                "footerText": "x",
                "visible": true,
                "noWrap": false,
                "rowSpan": -2147483648,
                "headerText": "x",
                "id": "form1:table1:rowGroup1:colSelector"
            },
            {
                "width": "100px",
                "footerText": "first",
                "visible": true,
                "noWrap": false,
                "rowSpan": -2147483648,
                "headerText": "first",
                "id": "form1:table1:rowGroup1:col0"
            },
            {
                "width": "100px",
                "footerText": "last",
                "visible": true,
                "noWrap": false,
                "rowSpan": -2147483648,
                "headerText": "last",
                "id": "form1:table1:rowGroup1:col1"
            },
            {
                "width": "100px",
                "footerText": "email",
                "visible": true,
                "noWrap": false,
                "rowSpan": -2147483648,
                "headerText": "email",
                "id": "form1:table1:rowGroup1:col2"
            }],
            "id": "form1:table1:rowGroup1",
            "headerText": "Authors",
            "paginationControls": true
        }],
        "maxRows": 3,
        "caption": "Address Book",
        "id": "form1:table1"
    };

    tableWidget.setProps(tableProperties);


While this may seem a complex thing to do, in reality it follows logical object hierarchy of data, and can be easily programmed, as we will see below.



Build widget data outside of JavaScript environment ( on the server)

JavaScript objects naturally convert to JSON representation. Thus widgets can easily be programmed with JavaScript on the client-side (browser). If a need arises for server to generate and transfer widget data, it can be done in absolutely any format – plain string, XML, HTML, JSON again, etc., etc.


For the demo, we have chosen JSON format to be generated and serialized across the wire. Virtually all modern programming languages support JSON data structure object mapping. JSON.org libraries have been used in the demo to serialize ( stringify) and parse JSON objects back and forth:


Continuing on the example of table, for which JSON object has been presented above, see addressbook/AddressBookServlet.java for details on how these JSON objects are built and serialized into the response stream. Basically, just few objects from “Json in Java” ( http://www.json.org/java/index.HTML) are used:


 //create table properties
 JSONObject tableWidgetProps = new JSONObject();
        
 tableWidgetProps.put("id", name);
 tableWidgetProps.put("maxRows", 3).put("caption", "Address Book");
 
  ...

 responseJson.put("form1:table1", tableWidgetProps);

and later:

//write response
responseJson.write(out);


<< Back to the List of Use Cases


Use Case 5: Form submit with Ajax ( mimic page submit)

Use Case

Summary: Mimic browser behavior by submitting all successful form elements to the form action URL, only with an Ajax call and without a page submit.

Actors: Controller (application business logic), HTML page, Server Controller (application business logic), connection

Prereq:

  1. (optional) Loaded Woodstock library ( see Use Case “Instantiate client-side widget from plain HTML markup”)

  2. (optional) Loaded Widget ( see Use Case “Instantiate client-side widget from plain HTML markup”)

Main Success Scenario:

  1. Client: Build the request string

  2. Client: Submit the request

  3. Server: parse the request and write the response

Alternative Scenario Extensions:

    • Submit any part of DOM tree structure, and not necessarily form

    • Control which data elements are to be submitted.

Notes and Questions

    • none

Implementation

Form in web application acts as a container for controls. It is customary in web application to use form as a submission unit. Upon submission, browser iterates over successful controls of a single form, builds up a request, submits it, and then updates pages with response. Woodstock widgets can be nested in regular forms, and submitted in such regular fashion. But this results in page update. Page data ( including widget data) can be submitted with Ajax call just as easily.

Note that modern libraries such as YahooUI or Prototype already offer such functionality. We just briefly overview the implementation.



Client: Build the request string

When browser submits the form, it builds the request. If one wants to submit a form with Ajax, such browser functionality needs to be 'recreated' with JavaScript. In the simplest case, we need to iterate over all the form element collection, and assemble a key-value map. Here, for example, is excerpt from YahooUI connection.js JavaScript method setForm():


for (var i=0; i<oForm.elements.length; i++){
    oElement = oForm.elements[i];
    oDisabled = oElement.disabled;
    oName = oElement.name;
    oValue = oElement.value;

    // Do not submit fields that are disabled or
    // do not have a name attribute value.
    if(!oDisabled && oName) {
        switch(oElement.type) {
            case 'radio':
            case 'checkbox':
                if(oElement.checked){
                    this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
                }
                  break;

             ...
            
             case 'reset':
                // stub case for input type reset button.

             ...




Client: Submit the request

Once data is collectied and put into a request string, it can be submitted exactly the same way as all other Ajax calls were made:


  c.setForm('form1',null, null);
  
  //make Ajax call      
  c.asyncRequest('POST', '/proto/EchoServlet', callback);                      


Demo application offers ability to submit the form by pressing “Submit Form with Ajax” button. As one can see from the script, data is submitted to plain EchoServlet.




Server: parse the request and write response

When request comes to the server, it looks exactly the same as it would come from browser page submit. It can be parsed for parameter names, etc. Demo's EchoServlet simply prints out the request parameters back to the response stream



Alternative Scenario

Note that form submission is not necessarily a requirement of web programming nowadays, and it remains a developer's choice to use forms for submission or to submit data without forms. Further, since collection of the data on the page for submission with Ajax now does not belong to the browser, developer can potentially choose or change rules of how data is collected upon 'custom form submission'. Realize though that this will break the rules established by HTML specification.

<< Back to the List of Use Cases


Use Case 6: ....(truncated)

For a full version of this document - see web\\design\\index.html in the downloaded archive

Comments:

hiiiiii

Posted by guest on June 02, 2008 at 10:03 PM MDT #

Hi, JSF 2.0 specs should try to focus on component JSON objects binding. Developers should work on JSON Proxy and framework injecting values into JSON proxies at run-time.

Component authors can write custom function in JSON binded beans and minimize the server calls.

This all thinking is key to making JSF 2.0 to be next generation specs and applications becoming more rich.

If JSF does not focus on this some other framework will do and surely it will be adopted by community.

All components should be light weight can be controlled client-side and server-side.

Everything has to be annotations based ( class-byte code instrumentation), no more XMLs and base classes please!!.

Charting support is nowhere ?? What kind of enterprise application are we thinking of in 2008.

I hope Java team plans to be very active in JSF 2.0 specs.

Posted by Rahul Mahajan on June 11, 2008 at 03:59 PM MDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Dmitry Kushner

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today