Mashups, beyond reporting

Build a form widget to use with IBM Mashup Center relational update feeds

Developers of all kinds may occasionally find a need to build an application that makes simple updates to a database table. This article describes how to build an IBM® Mashup Center widget that can display an HTML form that lets users update relational database tables. Optionally, you can quickly create your own mashup page by simply using the downloadable sample widget as is and supplying your own HTML form.

Share:

Louis Mau, Solutions Architect, IBM

Louis Mau is part of the InfoSphere MashupHub development team. His current focus is to help customers build situational applications using the IBM Mashup Center. Prior to this role, he was the architect for DB2 Everyplace Sync Server, which helps synchronize data from enterprise databases onto a small foot print database running on mobile devices.



Klaus Roder, Solutions Architect, IBM Mashup Center, IBM

Klaus Roder is a solutions architect for IBM Mashup Center at the IBM Silicon Valley Lab. His current focus is developing and deploying enterprise mashups with customers using IBM Mashup Center. Prior to his current role, he worked on the IBM Web Interface for Content Management (WEBI) project and the WebSphere Information Integrator Content Edition (IICE) development team. He holds a master's degree in computer science from the University of Applied Science in Würzburg and is a member of the San Francisco Bay Area ACM chapter.



19 August 2010

Also available in Chinese Russian Japanese Spanish

Overview

Most developers occasionally need to build an application that makes simple updates to a database table. Starting with Version 2 of the IBM Mashup Center, you can easily create a relational (JDBC) feed that can execute a single INSERT, UPDATE, or DELETE SQL statement. This article describes how to develop a widget that helps you to utilize such feeds in mashup applications.

This article assumes that you are already familiar with building mashups and feeds as well as the basics of writing a widget. In particular, you should know how to program in JavaScript and have experience using the IBM Mashup Center. The Resources section contains links to the following two items that provide good introductory information that can help get you up to speed on some of the basics of building mashups: "Creating a feed from an enterprise database (JDBC)" and "Developing widgets for IBM Mashup Center."

IBM Mashup Center database support

The IBM Mashup Center includes InfoSphere MashupHub and Lotus Mashups. It provides an out-of-the-box relational feed generator to create consumable feeds from most common database servers, including DB2®, Informix®, and IMS™.

Relational update feed

With IBM Mashup Center, you can create a feed from data that is returned from a relational query. The feed is created by selecting the tables and columns that you are interested in, or by using an SQL statement to query the database. The feed is created from the data that is returned in the query result set.

Starting with V2 of IBM Mashup Center, in addition to using SELECT SQL statements, you can also use the relational feed generator to execute an INSERT, UPDATE, or DELETE SQL statement. You can only execute a single SQL statement, so this feature does not lend itself to being used for complex transactional processing. However, you can use the update capability to support many relatively simple scenarios such as the following examples:

  • Taking a snapshot to perform trend analysis. For example, assume you have a feed that returns the total number of new orders for each day. By running and saving the feed content into a database table, you can generate a feed to show the order arrival trend. Using the data mashup editor, you could create a data mashup with a FOREACH operator to INSERT content from each repeating entry into its own row.)
  • Persisting comments or notes. For example, you could have a simple polling application to gather users' preferences or opinions.
  • Developing a form to maintain ToDo lists that are persisted in a database.
  • Developing a form to submit service requests. For example, these could be service requests for a building, a printer, or an IT system.

Sometimes, building a mashup page for the simple usage of a relational update feed is not straightforward. For example, you could use the User Input widget shipped with the IBM Mashup Center to generate controls such as textboxes to collect user inputs. However, the User Input widget cannot directly execute a relational update feed, and there is no widget that can display the results of the execution in a nice way.

This article describes how you can build a custom widget that makes it easy to use these relational update feeds for the second type of scenario listed above. The custom widget takes an HTML form as a configuration parameter. It renders the form, submits the form data to a relational update feed, and displays the update status. Because this custom widget accepts an arbitrary HTML form fragment, you have more control over the layout of the form. The use of an HTML form fragment also makes it easy to create the same form across multiple pages. The next section starts you off by describing the sample scenario used to illustrate the features of the HTML form widget.


Sample scenario

To minimize setup and make it easy to follow along, the sample scenario uses the policy table that comes with the Apache Derby sample database installed with the IBM Mashup Center. Figure 1 shows a screenshot of the sample mashup application that this article describes how to build. The application is fairly simple and consists of two widgets.

Figure 1. Sample Mashup page
Shows table on the left with policyid, customername, and coverage columns; on the right, the Policy Address Update and Delete form

As shown above in Figure 1, the DataViewer widget on the left is used to display a list of interested policies retrieved from the database. If a row (policy) is selected, detailed information about the policy is displayed in the HTML form widget on the right. Users can change the address and hit the submit button on the HTML form widget. The button is configured to execute a relational update feed. The result of the execution is an XML document. The XML document is parsed and a simple success or failure message is displayed. Figure 2 shows the success message.

If you want to get your hands on the sample widget right away and use it with your own form, get the sample widget from the Download section and add it to your IBM Mashup Center. Then you can skip the description on how to build the widget and jump right to the Putting it all together section.

Figure 2. Message shown on successful execution
Message shown on successful execution

Before you build the widget that would support the above functionality, you need to take care of one more thing: defining the relational feeds. The next section describes how you do that.


Creating the JDBC feeds

As mentioned earlier, to make it easy to follow along, the sample scenario described in this article uses the policy table that comes with the IBM Mashup Center sample database.

Follow these steps to create relational feeds for the policy table:

  1. Go to the Catalog Home Page and click Create.
  2. Select New Feed.
  3. Select Enterprise Database (JDBC) as the feed data source.
  4. To get to the database that contains the policy table, select Mashup Hub Sample Database in the Connection Profile field.

    If the profile does not exist yet, create it by providing the following information:

    • Connection Profile Name: MashupHub Sample Database
    • Database Type: Derby Embedded
    • Connection Type: Driver Manager (Non-managed Connection)
    • Database Name: <installDir>/Hub/installedApps/Mashup Hub.ear/mashuphub-enterprise.war/hubsample
  5. Use the following SQL statements to create two feeds that correspond to the two widgets shown in Figure 1:
    • The first feed is for the DataViewer widget that shows the list of policies. Note that adding the state parameter enables you to filter the policies for a given state.
      select * from samples.policyholders where state = ':state'
    • The second feed is for the relational update feed used by the HTML form widget.
      update samples.policyholders set address = ':address', city = ':city', 
      state = ':state' where policyid = ':policyid'

    The article assumes you are already familiar with using the IBM Mashup Center to create relational feeds. Because both of these queries use parameters, you need to create them by pasting the SQL statements into the Advanced box of the JDBC feed editor. The Resources section contains links that provide details on creating relational feeds.

Before proceeding, this is a good opportunity to review a few areas that sometimes require extra attention when you are using relational update feeds:

  • Use of HTTP GET.

    As explained in the W3C article listed in the Resources section, you should use HTTP POST when "the interaction changes the state of the resource in a way that the user would perceive (for example, a subscription to a service)." One reason for this is that HTTP GET URLs can be easily bookmarked and cached, which can result in accidental and unwanted invocation. The HTML form widget that you develop using this article uses HTTP POST as the access method. By default, the IBM Mashup Center enables both GET and POST support. You can disable HTTP GET access by expanding the Access Method button on the feed detail page and deselecting the GET checkbox.

  • Avoid duplicate rows.

    Relational update feeds consist of a single SQL statement. Because there is no error handling logic, you must rely on database constraints to ensure semantic integrity of the data. For example, to ensure that there are no duplicate rows, one of the columns should be declared as a KEY column so that any insertion of a row using a previously inserted key would fail.

  • Caching.

    In most cases, feeds that perform updates should not be cached. One exception is when the update feed is used in a data mashup. During editing, without caching, the update feed is executed whenever its output is previewed. By default, the source operator caches its input feed for an hour. This is exactly what you need during the mashup construction. Just before saving the completed mashup, you should turn off caching in all source operators that use relational update feeds.

With these preparations out of the way, you are now ready to build the custom HTML form widget.


Widget development

Mashup Center widgets follow the iWidget specification. There are two types of widgets. The main difference between them is the deployment method.

  • WAR file based widgets — these widgets can contain server based components and must be deployed on an application server.
  • Lightweight widgets — these widgets run completely on the client side and do not need to be deployed on an application server. The sample HTML form widget described in this article is a lightweight widget.

Follow these steps to begin development of the sample HTML form widget using IBM Mashup Center Version 2:

  1. As shown in Figure 3, click Go to View on the top right corner of the Mashup Builder page and select Create a New Widget....
    Figure 3. Create Widget menu
    screenshot of Mashup Builder page with Create a New Widget selection highlighted
  2. As shown in Figure 4, from the Widget Builder dialog, select Work with the widget editor.
    Figure 4. Widget Builder dialog
    Screenshot shows options to create a widget from a wizard, or work with the widget editor
  3. On the next dialog, select Create a new project.
  4. On the New Widget Project dialog, select Create a project from starter files. This creates a new project with a skeleton widget definition and catalog file. All the files are maintained by the server. As shown in Figure 5, the Customized Widget Project dialog shows the names of the files under the "Select a file" heading. Using the buttons below the list, you can select any existing file for edit or you can upload additional files into your project.
    Figure 5. Customized Widget Project dialog
    Screenshot shows list of files that can be selected
  5. When you are ready to test, click Export and select Add to palette.

The sample project for this article is fairly simple and contains only two files.


Widget definition file

You do not need to change the generated catalog.xml file. It simply provides the name of the widget as it appears in the toolbox menu and the location of the widget definition file (iWidget.xml). The iWidget.xml file specifies the JavaScript file that implements the logic, the static events sent or received by the widget, the layout in view mode, and the layout in edit mode. This section steps you through the changes you need to make to iWidget.xml to cover each of these areas.

Listing 1 shows the root element of the iWidget.xml file. The iScope attribute in the iwidget root element is the most significant. It specifies the JavaScript object that implements the iWidget callback functions. The file containing the JavaScript is loaded using the resource element. For details on these and other attributes, consult the widget programming and API documentation link in the Resources section.

Listing 1. iWidget.xml header
<iw:iwidget name="htmlForm"
            xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"
            iScope="sample.mashupcenter.htmlForm"
	    allowInstanceContent="true" supportedModes="view edit"
            mode="view" lang="en">

<iw:resource uri="htmlForm.js"/>

Listing 2 shows the definitions for the widget's one predefined receive event and two send events. The receive event is indicated by the presence of the handled and onEvent attributes. The value of the onEvent attribute is the name of the function to call when the event is received. The value of the published attribute defines the name of the published event. The Event handling and generation section later in this article describes how these events are handled.

Listing 2. iWidget.xml event specification
<iw:event id="ResetForm" handled="true" onEvent="handleReset"
          eventDescName="desc_handleReset"/>
<iw:eventDescription id="desc_handleReset" payloadType="any" title="Clear all Fields"
                        description="Clear all the fields in the form" lang="en">
</iw:eventDescription>

<iw:event id="actionSuccessful" eventDescName="desc_actionSuccessful" published="true"/>
<iw:eventDescription id="desc_actionSuccessful" payloadType="text"
                        description="Number of records updated by WebService" lang="en">
</iw:eventDescription>

<iw:event id="actionFailed" eventDescName="desc_actionFailed" published="true" />
<iw:eventDescription id="desc_actionFailed" payloadType="text"
                        description="Failure to assign" lang="en">
</iw:eventDescription>

Lastly, the widget definition file also specifies the widget layout for view and edit modes. The layout is specified by HTML markup included as CDATA in the iw:content element. Listing 3 shows the HTML markup for the view mode. Notice that all the div elements have an id so that you can manipulate them with JavaScript. Also, notice that the values of each id use _IWID_ as a prefix. At runtime, the IBM Mashup Center replaces all the _IWID_ prefixes with the actual unique widget instance id during widget creation. This ensures that all the ids are unique even if there are multiple instances of the widget on the same HTML page. There are two div elements in the view mode definition. The div with the id of _IWID_formdiv will contain an HTML form fragment and is initially blank. The other div has a style specification of display:none, which means it is not visible. It contains a template for displaying the result of the form submission and can be made visible by JavaScript after executing one of the update feeds.

Listing 3. iWidget.xml view mode layout
<iw:content mode="view">
  <![CDATA[
  <div id='_IWID_formdiv'></div>

  <div id='_IWID_resultdiv' style='display:none; font-size:1.3em;'>
      <div id="_IWID_ResultXML" ></div>
      <br />
      <a href=""
         onclick="javascript:iContext.iScope().showFormAndHideResult();return false;">
         Back</a>
  </div>

  ]]>
</iw:content>

The edit mode section contains the code for a form with one textarea and three textboxes. It is displayed when the user clicks Edit Settings. The textarea is used for entering the HTML form fragment. The three textboxes are for entering up to three URLs. A later section describes how to associate these URLs with buttons on the form. The URL values should be the same as what would be entered into the form method attribute. That is, the URL with the name value pairs following the ? character stripped out.

htmlForm Edit dialog shows a screenshot of the rendered form. For the sake of brevity, this article does not reproduce the entire edit mode HTML layout. It is available as part of the complete widget package that you can download from the appropriate link in the Resources section.


JavaScript implementation

The JavaScript implementation file is named htmlForm.js. It is a Dojo class that handles standard events such as load, unload, view, edit, and any other custom events and server communication. Following is a quick overview of the functions contained within the file:

  • onLoad— This function is where you place initialization code. Normally this would include retrieving configuration information saved in the previous invocation of the Edit Settings dialog.

    Recall that all id attributes in the HTML markup for view and edit modes contain the prefix _IWID_ that is replaced by the actual widget instance id when the widget is created. This means that before the JavaScript code can retrieve an HTML element identified by its id, the instance widget id from the iContext object must be used to construct the actual id. Notice how in Listing 4 the widget configuration data is retrieved from the widget attributes object associated with iContext.

    Listing 4. onLoad function
    onLoad: function() {
    
            this.uid = "_" + this.iContext.widgetId + "_";
    
            this.formDivNode   = dojo.byId(this.uid + 'formdiv');
            this.resultNode = dojo.byId(this.uid + 'resultdiv');
    
            // load attributes
            var attributes = this.iContext.getiWidgetAttributes();
            this.formHtml  = attributes.getItemValue( "formHtml" );
            ::::::::::::::::::::::::
    },
  • onUnload— This function is called just before a page is being switched out. Normally, no cleanup is necessary, which would mean that you do not need to implement this function. However, because Dojo V1.3 Dijit ids must be unique and are not automatically removed during cleanup when switching between pages, you need to do this manually.
    Listing 5. onUnload function
    onUnload: function()
    {
        // need to clear all existing dijits (to free up id's)
        if ( this.formDijit != null )
            this.formDijit.destroyRecursive( false );
    },
  • onview— This function is called whenever the widget is displayed. The sample widget simply displays a default message if the widget has not been configured (for example, when it is first dragged onto the page). The other functions are explained in detail in the following sections.
    Listing 6. onview function
    onview: function()
    {
        if ( this.formHtml == null  ||  this.formHtml.length <= 0 ) {
            this.formDivNode.innerHTML = "Switch To Edit to specify HTML form";
        } else if ( this.viewContent.length <= 0 ) {
            this.displayForm();
            this.reCreateEvents( );
        }  // else form already there, no need to do anything
    },
  • onedit— This function is called when Edit Settings is clicked. The code in Listing 7 simply pre-populates the Edit Settings dialog with values supplied by the user from any previous invocation.
    Listing 7. onedit function
    onedit: function()
    {
        dojo.byId( this.uid + "formHtml" ).value = this.formHtml;
        :::::::::::::::::::::::::::::::::::
    },
  • saveConfigData— This function does not correspond to any built in event. It is a widget-specific function specified in the Save button onclick method of the edit mode HTML markup. The code in Listing 8 simply retrieves and saves the latest user supplied values from the Edit Settings dialog. The onModeChanged event is used to inform the widget runtime to dismiss the Edit Settings dialog.
    Listing 8. saveConfigData function
    saveConfigData: function()
    {
        this.formHtml = dojo.byId( this.uid + "formHtml" ).value;
        ::::::::::::::::::::::::::::::::::::::::::::::::::
    
        this.iContext.iEvents.fireEvent("onModeChanged", null, "{newMode:'view'}");
    
        var attributes = this.iContext.getiWidgetAttributes();
        attributes.setItemValue("formHtml"  ,  this.formHtml );
        ::::::::::::::::::::::::::::::::::::::::::::::::::
        attributes.save();
    },

The Resources section contains a link you can use to download the complete widget package. Now that you are familiar with the functions common to all widgets, the next section takes you through the functions that are specific to the sample widget.


Displaying the HTML form

To use the widget, you need to provide an HTML form. You can create the form using any editor or code generation tool that you like. After creating the HTML form, make sure it has the appropriate dojotype attribute for each of the form input fields. (For an example, refer to the sample HTML listing in the Putting it All together section.) Your form can have multiple buttons. For a button to be active, it must provide an onclick attribute with a value similar to the following:

            onclick="_${widgetId}_iContext.iScope().submit('formUrl1');"

The above is the syntax to call the submit function defined in the widget's JavaScript file. The Handling form submission section describes the details of how the submit function is handled. For now, just replace the ${widgetId} substring in the example above with the actual id for your widget so that it is valid JavaScript. How this is done is what is covered next.

To display the HTML form fragment pasted into the Edit Settings dialog, you simply assign the HTML string to the innerHTML of the iWidget.xml view mode layout placeholder div as shown in Listing 9. But before you can do that, you need to replace the ${widgetId} string with the actual widget id. Do this by calling the Dojo string utility function substitute. This is also shown in Listing 9. The last thing to note about the code in Listing 9 is that because the form contains Dojo Dijits, you have to call the Dojo parse method for the Dojo behavior to take effect.

Listing 9. displayForm function
displayForm: function()
{
    // fix up button onclick action to point to submit method of this widget.
    this.viewContent = dojo.string.substitute( this.formHtml
                                             , { widgetId: this.iContext.widgetId });
"
    // Add form content to the view content root node.
    if ( this.formDijit != null )  // need to clear all existing dijits (to free up id's)
        this.formDijit.destroyRecursive( false );
    this.formDivNode.innerHTML = this.viewContent;

    // Parse dojo components to display Dojo widgets
    dojo.parser.parse( this.formDivNode );
    this.formDijit = this.getFormDijit(  this.formDivNode );
},

Event handling and generation

One key feature of the sample HTML form widget is that you can wire data into the widget. As described in the Sample scenario section, clicking a row of the DataViewer widget causes the columns of the row to be passed to the form input fields of the widget. Because the form input fields can vary from form to form, you cannot define receive events for the input form fields statically in the iWidget.xml file like you did for the predefined receive event and two send events in the iWidget.xml event specification.

To create the events dynamically for each of the form input fields, you first need to parse the supplied HTML for all form input fields, as shown in Listing 10.

Listing 10. createEventsForFields function
createEventsForFields : function(  )
{   
    this.eventNames = [];
    this.dijitMap   = {};

    var children = this.formDijit.getChildren();
    for (var i = 0  ;  i < children.length  ;  i++ ) {
        var widget = children[i];
        var name  = widget.attr( 'name' );
        if ( name == null ||  name.length == 0 )
            continue;  // skip over unnamed form input fields
        if ( widget.type == 'radio'  &&  widget.checked == false )
            continue;   // for radio button, pick the one that is true

After you have identified a form input field, create an event for it with the same name, as shown in Listing 11.

Listing 11. Dynamically creating events
this.eventNames.push( name );
this._createEvent({
    name : name,
    type: "any",
    isHandled : true,
    handlingFn : dojo.hitch(this, this.handleEvent )
});

At the end of the for loop, add each event to a dijitMap, as shown in Listing 12. You will use this map later on to fire the right event when an event is called.

Listing 12. dijitMap to store event names
// will also create dijit mapping to process event
this.dijitMap[ name ] = widget;

Next, you need to put in place the code to handle these events when they are fired. When one of the specific events shown above is wired to the widget, the event name is used to find (with the help of the dijitMap code) the correct form input field. If the form input field is not null, set the payload you receive as the widget value, as shown in Listing 14

Listing 14. handleEvent function
handleEvent: function(iEvent){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    var  evtname    = iEvent.name;
    var  widget     = this.dijitMap[ evtname ];
    if ( widget != null )
        widget.setValue( iEvent.payload ); 
}

Handling form submission

As mentioned in the Displaying the HTML form section, buttons in the HTML form fragment must include an explicit call to the submit function. The argument to the submit function defines which feed URL defined on the htmlForm Edit dialog is executed when the button is pressed. As shown in Listing 15, the argument must be one of the following strings:

  • formUrl1— Execute the feed URL defined for First form method.
  • formUrl2— Execute the feed URL defined for Second form method.
  • formUrl3— Execute the feed URL defined for Third form method.
Listing 15. submit function
submit: function( action ) {
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    var actionURL = "";
    //Specify the root URL of the feed that you want to trigger:
    if ( action == 'formUrl1' ) {
        if (  this.formUrl1  &&  this.formUrl1.length > 0 )
            actionURL = this.formUrl1;
    } else if ( action == 'formUrl2' ) {
        if (  this.formUrl2  &&  this.formUrl2.length > 0 )
            actionURL = this.formUrl2;
    } else if ( action == 'formUrl3' ) {
        if (  this.formUrl3  &&  this.formUrl3.length > 0 )
            actionURL = this.formUrl3; 
    ::::::::::::::::::::::::::::::::::::::::::::::::::

Now that you have the correct base URL for the selected action, you need to collect the form values entered by users. This is done with the collectNVP function. As shown in Listing 16, all the tedious work to retrieve values from the different kinds of input form fields is handled by the Dojo library form Dijit getValues function. Your code just needs to loop through the fields and encode the values to make sure that there are no invalid characters.

Listing 16. collectNVP function
collectNVP: function(  ) {
    this.debugTrace( "collectNVP entered" );

    var formData = "";
    var temp = this.formDijit.getValues();
    for ( var  name in temp ) {
        if ( formData.length > 1 )  formData += '&';
        //Encode the key and value, to make sure there are no invalid characters.
        formData +=  encodeURI( name );
        formData +=  "=";
        // encodeURI( value );   doesn't escape &, ...
        var value =  temp[ name ];
        formData +=  escape( value );
    }
    return formData;
}

After you have gathered form data and the base URL, you submit the AJAX call by using the Dojo library xhrPost method. As per the advice in the Creating the JDBC feeds section, use HTTP Post as the access method rather than HTTP GET to execute the relational update feed.

As shown in Listing 17, the arguments to the xhrPost method include call back functions for the load (success) and error cases. Details of these call back functions are described in the following two sections. The urlToLoad argument, which contains the base URL or form method, is not used directly. This is because the browser sandbox rule requires that the user-supplied base URL be redirected to go through the Mashup Server AJAX proxy. This is achieved by calling the reWriteURI function accessible through iContext.

Listing 17. Form submission
// Using POST for update type URL
submitUrl: function(urlToLoad, formdata )
    var location = this.iContext.io.rewriteURI( urlToLoad );
    dojo.xhrPost({
        url     : location,
        postData: formdata,
        load    :  dojo.hitch( this, this.handleFeedContent ),
        error   :  dojo.hitch( this, this.handleErrorResponse ),
        handleAs: "xml",
        sync    : true
    });
}

Handle a successful form data submission

As specified in the xhrPost AJAX call, the handleFeedConent function is called when the form is submitted successfully. This widget is designed to work only with the MashupCenter relational (JDBC) update feed. The feed returns the XML response shown in Figure 6. If a different response is retrieved, the program displays a message indicating that an "Unsupported result format" was returned.

Figure 6. Successful update feed response
xml snippet with executionreslut top element with rowcount element and value of 1 and empty systemmsg element

As shown in Listing 18, if the correct format is returned, the handleFeedConent function displays the message "Operation successful" and the number of rows that were successfully inserted. The function also fires the actionSuccessful event, which is defined statically in the iWidget.xml file described earlier in the Widget definition file section.

Listing 18. successful Form submission
handleFeedContent: function(data){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    resultHTML += "Operation successful.";
    resultHTML += rowCount;
    resultHTML += " record(s) changed.";

    this.iContext.iEvents.fireEvent("actionSuccessful", null, "" );
    ::::::::::::::::::::::::::::::::::::::::::::::::::

As shown in Listing 19, if the MashupCenter Relational (JDBC) plug-in call returns an error (-1), the handleFeedConent function generates a result string with the message returned in the systemmsg element. It also fires the actionFailed event that is defined in the the iWidget.xml event specification.

Listing 19. Error message returned after successful Form submission
handleFeedContent: function(data){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    if (  rowCount ==  "-1" ) {

       var  msg     = "Unknown error. <br><br>";
       var  msgList = dojo.query( "systemmsg" , data );
       if ( msgList  &&  msgList[0] )
            msg = dojox.xml.parser.textContent( msgList[0] );
       resultHTML += msg;

       this.iContext.iEvents.fireEvent("actionFailed", null, rowCount );

Handle errors during the form data submission

As shown in Listing 20, if the form data submission fails, the handleErrorResponse function displays the results returned from the communication failure by calling displayResult.

Listing 20. handleErrorResponse function
handleErrorResponse: function(data)
{
    this.debugTrace( "handleErrorResponse entered data="  + data );
    this.displayResult( data );
}

Displaying the form submission results

In both cases, whether the form submission was successful or had errors, the displayResult function is used to remember the form size, hide the current input form, and show the form submission results.

The style definition for the resultNode is initially defined in the iWidget.xml view mode layout as display:none, which causes it to be hidden. As shown in Listing 21, the displayResult function makes the resultNode visible by changing its style.display definition to block.

Listing 21. displayResult function
displayResult: function(data)
{
    // save the current size
    var  formSize = dojo.contentBox( this.formDivNode );
    // hide the form
    this.formDivNode.style.display = "none";

    // show the result
    this.resultNode.style.display = "block";
    dojo.contentBox( this.resultNode, formSize );
    var resultXmlNode = dojo.byId(this.uid + 'ResultXML');
    resultXmlNode.innerHTML = data;
},

The resultdiv includes a Back link that calls the showFromAndHideResult function. As shown in Listing 22, this function hides the resultdiv and shows the form again.

Listing 22. showFormAndHideResult function
//Clear data, hide the result node, and show the form again.
showFormAndHideResult: function()
{
    this.debugTrace( "handleFeedContent entered" );

    this.formDivNode.style.display = "block";

    // clear any message text
    var resultXmlNode = dojo.byId(this.uid + 'ResultXML');
    resultXmlNode.innerHTML = "";
    this.resultNode.style.display = "none";
},

Putting it all together

You are now ready to incorporate your HTML form widget into the sample mashup application described in the Sample scenario section. Begin with the HTML form fragment for the policy record. As shown in Listing 23, use an HTML table to organize the textboxes. As was described earlier, the form must use Dojo Dijits. Just as on a normal HTML page, the input form fields must have names that match the name of the parameters used in the relational update feed. You created the feed earlier in the Creating the JDBC feeds section. The form can have multiple buttons corresponding to any combination of INSERT, UPDATE, or DELETE actions. To illustrate the possibility for further extension, the form contains an extra non-functional button labeled Delete Policy that does not have a corresponding feed.

Listing 23. Policy HTML Form
<form dojotype="dijit.form.Form" style="font-size:1.3em;">

  <div style='background-color:#D1EACC; height:4em; padding-top:5px; padding-bottom:5px'>
      <center><h3>Policy Address Update and Delete Form</h3></center>
  </div>

  <br>
  <table>

  <tr><td>Policy Id:</td>
      <td><input type="text"  name="policyid"  dojotype="dijit.form.TextBox"
                 style="width: 6em;" readonly /></td>
      <td></td>
      <td></td>
  </tr>

           :::::::::::::::::::::::::::::::::::::::::

  <tr>
  <td></td>
  <td colspan='4' align='right'>
      <button dojotype="dijit.form.Button" value="formUrl1">Update Address
              onclick="_${widgetId}_iContext.iScope().submit('formUrl1');"
      </button>
      <button dojotype="dijit.form.Button" value="formUrl2">Delete policy</button>
  </td>
  </tr>
  </table>
</form>

Now, as shown in Figure 7, go to the htmlForm Edit dialog and paste the HTML form fragment into the Form Html field, and paste the relational feeds that you created in the Create the JDBC feeds section into the corresponding form method fields. Click Save to complete the configuration of the widget.

Figure 7. htmlForm Edit dialog
Screenshot of the htmlForm Edit dialog with HTML fragment textarea and textboxes for relational feeds

All the input fields are populated when a row from the DataViewer widget is selected. As explained in the Event handling and generation section, the HTML form widget dynamically creates receive events for each of the input form fields. All you need to do is to wire them to the DataViewer send events. Figure 8 shows the wiring of one of the generated receive events to the corresponding one from the DataViewer widget.

Figure 8. Receive events wiring
Screenshot of Wiring dialog linking htmlForm to ResetForm

Finally, you need to wire the actionSuccessful event from the HTML form widget to a URL Customizer widget. The latter is wired to the DataViewer widget and configured to use the same URL as what is used for the DataViewer. Figure 9 shows the URL customizer and the Wiring Graph.

Figure 9. URL Customizer and Wiring Graph
Screenshot of the Wiring Graph interface with htmlForm wired to URL Customizer wired to Data Viewer

After a successful update operation, the event is fired and the DataViewer is automatically refreshed. This is just for illustration in the case of this sample, because the sample's update operation does not change what is displayed in the DataViewer.

Figure 10. Send Events wiring
Screenshot of the Wiring dialog showing send event wired to widget to receive content

Conclusion

This article has taken you through the basic steps of constructing a widget, including dynamic event registration and server communication. To try and expand on what you learned from this article, you could enhance the widget with more elaborate failure handling for the relational update feed.

Mashup applications are often dashboards displaying information from disparate sources. Using relational update feeds together with this widget, you can quickly build mashup applications that not only provide reporting, but also provide a means to make simple update actions.


Download

DescriptionNameSize
Sample code for this articleHTMLformWidget.zip8KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Information management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management, Lotus
ArticleID=512076
ArticleTitle=Mashups, beyond reporting
publish-date=08192010