Chapter: Internet & World Wide Web HOW TO PROGRAM - The Ajax Client - Ajax-Enabled Rich Internet Applications

| Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail |

Dojo Toolkit

Developing web applications in general, and Ajax applications in particular, involves a certain amount of painstaking and tedious work.

Dojo Toolkit

 

Developing web applications in general, and Ajax applications in particular, involves a certain amount of painstaking and tedious work. Cross-browser compatibility, DOM manip-ulation and event handling can get cumbersome, particularly as an application’s size increases. Dojo is a free, open source JavaScript library that takes care of these issues. Dojo reduces asynchronous request handling to a single function call. Dojo also provides cross-browser DOM functions that simplify partial page updates. It covers many more areas of web development, from simple event handling to fully functional rich GUI controls.

To install Dojo, download the Dojo version 0.4.3 from  www.Dojotoolkit.org/down- loads to your hard drive. Extract the files from the archive file you downloaded to your web development directory or web server. Including the dojo.js script file in your web application will give you access to all the Dojo functions. To do this, place the following script in the head element of your XHTML document:

 

<script type = "text/javascript" src = "path/Dojo.js">

 

where path is the relative or complete path to the Dojo toolkit’s files. Quick installation instructions for Dojo are provided at Dojotoolkit.org/book/Dojo-book-0-9/part-1-life-Dojo/quick-installation.

 

Figure 15.11 is a calendar application that uses Dojo to create the user interface, com-municate with the server asynchronously, handle events and manipulate the DOM. The application contains a calendar control that shows the user six weeks of dates (see the screen captures in Fig. 15.11). Various arrow buttons allow the user to traverse the cal-endar. When the user selects a date, an asynchronous request obtains from the server a list of the scheduled events for that date. There is an Edit button next to each scheduled event. When the Edit button is clicked, the item is replaced by a text box with the item’s content, a Save button and a Cancel button. When the user presses Save, an asynchronous request saves the new value to the server and displays it on the page. This feature, often referred to as edit-in-place, is common in Ajax applications. You can test-drive this application at test.deitel.com/examples/iw3htp4/ajax/fig15_11/calendar.html.

 

1    <?xml version = "1.0" encoding = "utf-8"?>

 

2    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"

 

3           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

4              

5    <!-- Fig. 15.11 Calendar.html -->

 

6    <!-- Calendar application built with dojo. -->

 

7    <html xmlns = "http://www.w3.org/1999/xhtml">

 

8    <head>

 

9           <script type = "text/javascript" src = "/dojo043/dojo.js"></script>

 

10         <script type = "text/javascript" src = "json.js"></script>

 

11         <script type = "text/javascript">

12               <!--

 

13               // specify all the required dojo scripts

 

14               dojo.require( "dojo.event.*" ); // use scripts from event package

 

15               dojo.require( "dojo.widget.*" ); // use scripts from widget package

 

16               dojo.require( "dojo.dom.*" ); // use scripts from dom package

 

17               dojo.require( "dojo.io.*" ); // use scripts from the io package

18

19               // configure calendar event handler

 

20               function connectEventHandler()

21               {

 

22                      var calendar = dojo.widget.byId( "calendar" ); // get calendar

 

23                      calendar.setDate( "2007-07-04" );

 

24                      dojo.event.connect(

25                            calendar, "onValueChanged", "retrieveItems" );

 

} // end function connectEventHandler

 

28               // location of CalendarService web service

 

29               var webServiceUrl = "/CalendarService/CalendarService.asmx";

30          

31               // obtain scheduled events for the specified date

 

32               function retrieveItems( eventDate )

33               {

 

34                      // convert date object to string in yyyy-mm-dd format

 

35                      var date = dojo.date.toRfc3339( eventDate ).substring( 0, 10 );

36          

37                        // build parameters and call web service

 

38                      var params = ’[{ "param":"eventDate", "value":"’ +

39                            date +  "'}]";

 

40                      callWebService( 'getItemsByDate', params, displayItems );

 

41               } // end function retrieveItems

42

43                 // call a specific web service asynchronously to get server data

 

44               function callWebService( method, params, callback )

45               {

 

46                      // url for the asynchronous request

 

47                      var requestUrl = webServiceUrl + "/" + method;

 

48                      var params = paramString.parseJSON();

49

50                      // build the parameter string to append to the url

 

51                      for ( var i = 0; i < params.length; i++ )

{

53        // check if it is the first parameter and build

54        // the parameter string accordingly

55        if ( i == 0 )

56        requestUrl = requestUrl + "?" + params[ i ].param +

57        "=" + params[ i ].value; // add first parameter to url

58        else

59        requestUrl = requestUrl + "&" + params[ i ].param +

60        "=" + params[ i ].value; // add other parameters to url

61        } // end for

62       

63                      // call asynchronous request using dojo.io.bind

 

64                      dojo.io.bind( { url: requestUrl, handler: callback,

65                            accept: "application/json; charset=utf-8" } );

 

66               } // end function callWebService

67

68               // display the list of scheduled events on the page

 

69               function displayItems( type, data, event )

70               {

 

71                      if ( type == 'error' ) // if the request has failed

72                      {

73                            alert( 'Could not retrieve the event' ); // display error

 

74                      } // end if

75                      else

{

var placeholder = dojo.byId( "itemList" ); //           get placeholder

placeholder.innerHTML = ''; // clear placeholder

var items = data.parseJSON(); // parse server     data

81        // check whether there are events;

82        // if none then display message

83        if ( items == "" )

84        {                                  

85        placeholder.innerHTML = 'No events for this date.';

86        }                                  

87                                           

88        for ( var  i = 0; i < items.length; i++ )

89        {                                  

90        // initialize item's container

91        var item = document.createElement( "div" );

92        item.id = items[ i ].id; // set DOM id to database id

93                                           

94        // obtain and paste the item's description

95        var text = document.createElement( "div" );

96        text.innerHTML =  items[i].description;

97        text.id = 'description' + item.id;

98                    dojo.dom.insertAtIndex( text, item, 0 );                 

99                                           

100     // create and insert the placeholder for the edit button

101                 var buttonPlaceHolder = document.createElement( "div" );    

102                 dojo.dom.insertAtIndex( buttonPlaceHolder, item, 1 ); 

103                                        

104                 // create the edit button and paste it into the container

105                 var editButton = dojo.widget.         

106                 createWidget( "Button", {}, buttonPlaceHolder );           

107                 editButton.setCaption( "Edit" );     

108                 dojo.event.connect(

109                 editButton, 'buttonClick', handleEdit );    

110                                        

111     // insert item container in the list of items container

112     dojo.dom.insertAtIndex( item, placeholder, i );

113                         } // end for

114                   } // end else

 

115            } // end function displayItems

116      

117            // send the asynchronous request to get content for editing and

118            // run the edit-in-place UI

 

119            function handleEdit( event )

120            {

 

121                   var id = event.currentTarget.parentNode.id; // retrieve id

 

122                   var params = '[{ "param":"id", "value":"’ + id +  ’"}]’;

 

123                   callWebService( 'getItemById', params, displayForEdit );

 

124            } // end function handleEdit

125

126            // set up the interface for editing an item

 

127            function displayForEdit(type, data, event)

128            {

 

129                   if ( type == 'error' ) // if the request has failed

130                   {

 

131                         alert( 'Could not retrieve the event' ); // display error

}

 

133                   else

134                   {

 

135                         var item = data.parseJSON(); // parse the item

 

136                         var id = item.id; // set the id

137

138                         // create div elements to insert content

 

139                         var editElement = document.createElement( 'div' );

 

140                         var buttonElement = document.createElement( 'div' );

141      

142                         // hide the unedited content

 

143                         var oldItem = dojo.byId( id ); // get the original element

 

144                         oldItem.id = 'old' + oldItem.id; // change element's id

 

145                         oldItem.style.display = 'none'; // hide old element

 

146                         editElement.id = id; // change the "edit" container's id

147      

148                         // create a textbox and insert it on the page

 

149                         var editArea = document.createElement( 'textarea' );

 

150                         editArea.id = 'edit' + id; // set textbox id

 

151                         editArea.innerHTML = item.description; // insert description

 

152                         dojo.dom.insertAtIndex( editArea, editElement, 0 );

153

154                         // create button placeholders and insert on the page

 

155                         // these will be transformed into dojo widgets

 

156                         var saveElement = document.createElement( 'div' );

 

157                         var cancelElement = document.createElement( 'div' );

 

158                         dojo.dom.insertAtIndex( saveElement, buttonElement, 0 );

 

159                         dojo.dom.insertAtIndex( cancelElement, buttonElement, 1 );

 

160                         dojo.dom.insertAtIndex( buttonElement, editElement, 1 );

161      

162                         // create "save" and "cancel" buttons

 

var saveButton =

164     dojo.widget.createWidget( "Button", {}, saveElement );

165     var cancelButton =

166     dojo.widget.createWidget( "Button", {}, cancelElement );

167                         saveButton.setCaption( "Save" ); // set saveButton label

 

168                         cancelButton.setCaption( "Cancel" ); // set cancelButton text

169      

170                         // set up the event handlers for cancel and save buttons

 

171                         dojo.event.connect( saveButton, 'buttonClick', handleSave );

 

dojo.event.connect(

173     cancelButton, 'buttonClick', handleCancel );

174    

175                         // paste the edit UI on the page

 

176                         dojo.dom.insertAfter( editElement, oldItem );

177                   } // end else

 

178            } // end function displayForEdit

179

180            // sends the changed content to the server to be saved

 

181            function handleSave( event )

182            {

 

183                   // grab user entered data

 

184                   var id = event.currentTarget.parentNode.parentNode.id;

 

185                   var descr = dojo.byId( 'edit' + id ).value;


186

187                   // build parameter string and call the web service

 

188                   var params = '[{ "param":"id", "value":"' + id +

 

189                         '"}, {"param": "descr", "value":"' + descr + '"}]';

 

190                   callWebService( 'Save', params, displayEdited );

 

191            } // end function handleSave

192

193            // restores the original content of the item

 

194            function handleCancel( event )

195            {

 

196                   var voidEdit = event.currentTarget.parentNode.parentNode;

 

197                   var id = voidEdit.id; // retrieve the id of the item

 

198                   dojo.dom.removeNode( voidEdit, true ); // remove the edit UI

 

199                     var old = dojo.byId( 'old' + id ); // retrieve pre-edit version

 

200                   old.style.display = 'block'; // show pre-edit version

 

201                   old.id = id; // reset the id

 

202            } // end function handleCancel

203

204            // displays the updated event information after an edit is saved

 

205            function displayEdited( type, data, event )

206            {

 

207                   if ( type == 'error' )

208                   {

 

209                         alert( 'Could not retrieve the event' );

210                   }

211                   else

212                   {

 

213                           editedItem = data.parseJSON(); // obtain updated description

 

214                         var id = editedItem.id; // obtain the id

 

215                         var editElement = dojo.byId( id ); // get the edit UI

 

216                         dojo.dom.removeNode( editElement, true ); // delete edit UI

 

217                         var old = dojo.byId( 'old' + id ); // get item container

218      

219                         // get pre-edit element and update its description

 

220                         var oldText = dojo.byId( 'description' + id );

 

221                         oldText.innerHTML = editedItem.description;

222

223                         old.id = id; // reset id

 

224                         old.style.display = 'block'; // show the updated item

225                   } // end else

 

226            } // end function displayEdited

227

228            // when the page is loaded, set up the calendar event handler

 

229            dojo.addOnLoad( connectEventHandler );

230            // -->

 

231      </script>

 

232      <title> Calendar built with dojo </title>

 

233     </head>

234     <body>

 

235      Calendar

 

236      <div dojoType = "datePicker" style = "float: left"

 

237            widgetID = "calendar"></div>

 

<div id = "itemList" style = "float: left"></div>

239     </body>

 

240     </html>

 





Fig. 15.11 | Calendar application built with Dojo

Loading Dojo Packages

Lines 9–17 load the Dojo framework. Line 9 links the dojo.js script file to the page, giv-ing the script access to all the functions in the Dojo toolkit. Dojo is organized in packages of related functionality. Lines 14–17 use the dojo.require call, provided by the dojo.js script to include the packages we need. The dojo.io package functions communicate with the server, the dojo.event package simplifies event handling, the dojo.widget package provides rich GUI controls, and the dojo.dom package contains additional DOM func-tions that are portable across many different browsers.

 

The application cannot use any of this functionality until all the packages have been loaded. Line 229 uses the dojo.addOnLoad method to set up the event handling after the page loads. Once all the packages have been loaded, the connectEventHandler function (lines 20–26) is called.

 

Using an Existing Dojo Widget

 

A Dojo widget is any predefined user interface element that is part of the Dojo toolkit. The calendar control on the page is the DatePicker widget. To incorporate an existing Dojo widget onto a page, you must set the DojoType attribute of any HTML element to the type of widget that you want it to be (line 236). Dojo widgets also have their own wid-getID property (line 237). Line 22 uses the dojo.widget.byId method, rather than the DOM’s document.getElementById method, to obtain the calendar widget element. The dojo.events.connect method links functions together. Lines 24–25 use it to connect the calendar’s onValueChanged event handler to the retrieveItems function. When the user picks a date, a special onValueChanged event that is part of the DatePicker widget calls retrieveItems, passing the selected date as an argument. The retrieveItems function (lines 32–41) builds the parameters for the request to the server, and calls the callWeb-Service function. Line 35 uses the dojo.date.toRfc3339 method to convert the date passed by the calendar control to yyyy-mm-dd format.

 

Asynchronous Requests in Dojo

 

The callWebService function (lines 44–66) sends the asynchronous request to the spec-ified web-service method. Lines 47–61 build the request URL using the same code as Fig. 15.9. Dojo reduces the asynchronous request to a single call to the dojo.io.bind method (lines 64–65), which works on all the popular browsers such as Firefox, Internet Explorer, Opera, Mozilla and Safari. The method takes an array of parameters, formatted as a JavaScript object. The url parameter specifies the destination of the request, the han-dler parameter specifies the callback function, and the mimetype parameter specifies the format of the response. The handler parameter can be replaced by the load and error parameters. The function passed as load handles successful requests and the function passed as error handles unsuccessful requests.

 

Response handling is done differently in Dojo. Rather than calling the callback func-tion every time the request’s readyState property changes, Dojo calls the function passed as the “handler” parameter when the request completes. In addition, in Dojo the script does not have access to the request object. All the response data is sent directly to the call-back function The function sent as the handler argument must have three parameters— type, data and event.

 

In the first request, the function displayItems (lines 69–115) is set as the callback function. Lines 71–74 check if the request is successful, and display an error message if it isn’t. Lines 77–78 obtain the place-holder element (itemList), where the items will be dis-played, and clear its content. Line 79 converts the JSON response text to a JavaScript object, using the same code as the example in Fig. 15.9.

 

Partial Page Updates Using Dojo’s Cross-Browser DOM Manipulation Capabilities

 

The Dojo toolkit (like most other Ajax libraries) provides functionality that enables you to manipulate the DOM in a cross-browser portable manner. Lines 83–86 check if the server-side returned any items, and display an appropriate message if it didn’t. For each item object returned from the server, lines 91–92 create a div element and set its id to the item’s id in the database. Lines 95–97 create a container element for the item’s descrip-tion. Line 98 uses Dojo’s dojo.dom.insertAtIndex method to insert the description ele-ment as the first element in the item’s element.

 

For each entry, the application creates an Edit button that enables the user to edit the event’s content on the page. Lines 101–109 create a Dojo Button widget programmati-cally. Lines 101–102 create a buttonPlaceHolder div element for the button and paste it on the page. Lines 105–106 convert the buttonPlaceHolder element to a Dojo Button widget by calling the dojo.widget.createWidget function. This function takes three parameters—the type of widget to be created, a list of additional widget parameters and the element which is to be converted to a Dojo widget. Line 107 uses the button’s set-Caption method to set the text that appears on the button. Line 112 uses the insertAt-Index method to insert the items into the itemList placeholder, in the order in which they were returned from the server.

 

Adding Edit-In-Place Functionality

 

Dojo Button widgets use their own buttonClick event instead of the DOM onclick event to store the event handler. Lines 108–109 use the dojo.event.connect method to connect the buttonClick event of the Dojo Button widget and the handleEdit event han-dler (lines 119–124). When the user clicks the Edit button, the Event object gets passed to the event handler as an argument. The Event object’s currentTarget property contains the element that initiated the event. Line 121 uses the currentTarget property to obtain the id of the item. This id is the same as the item’s id in the server database. Line 123 calls the web service’s getItemById method, using the callWebService function to obtain the item that needs to be edited.

 

Once the server responds, the function displayForEdit (lines 127–178) replaces the item on the screen with the user interface used for editing the item’s content. The code for this is similar to the code in the displayItems function. Lines 129–132 make sure the request was successful and parse the data from the server. Lines 139–140 create the con-tainer elements into which we insert the new user-interface elements. Lines 143–146 hide the element that displays the item and change its id. Now the id of the user-interface ele-ment is the same as the id of the item that it’s editing stored in the database. Lines 149– 152 create the text-box element that will be used to edit the item’s description, paste it into the text box, and paste the resulting text box on the page. Lines 156–173 use the same syntax that was used to create the Edit button widget to create Save and Cancel button widgets. Line 176 pastes the resulting element, containing the text box and two buttons, on the page.

 

When the user edits the content and clicks the Cancel button, the handleCancel function (lines 194–202) restores the item element to what it looked like before the button was clicked. Line 198 deletes the edit UI that was created earlier, using Dojo’s removeNode function. Lines 200–201 show the item with the original element that was used to display the item, and change its id back to the item’s id on the server database.

 

When the user clicks the Save button, the handleSave function (lines 181–191) sends the text entered by the user to the server. Line 185 obtains the text that the user entered in the text box. Lines 188–190 send to the server the id of the item that needs to be updated and the new description.

 

Once the server responds, displayEdited (lines 205–226) displays the new item on the page. Lines 214–217 contain the same code that was used in handleCancel to remove the user interface used to edit the item and redisplay the element that contains the item. Line 221 changes the item’s description to its new value.

 

 

 

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.