What's new in Dojo Mobile 1.8, Part 3: Data-handler enhancements

Develop dynamic mobile applications with custom data handlers

Dojo Mobile (dojox.mobile) is a Dojo Toolkit package for creating lightweight mobile web applications. Dojo 1.8, released in August 2012, includes new widgets, widget enhancements, and other new capabilities. This article is the third in a three-part series that explores many of those new features, with ample code examples. In Part 3, see how Dojo Mobile 1.8 structures data handlers to be customizable and extensible, and learn how to create and register a custom content handler.

Yoshiroh Kamiyama (kami@jp.ibm.com), Software Engineer, IBM

Photo of Yoshiroh KamiyamaYoshiroh Kamiyama is an Advisory Software Engineer at Yamato Software Lab (YSL), IBM Japan. He works on WebSphere Feature Pack for Web 2.0 and Mobile, and previously worked on several development projects including Mobile Mashup, Lotus iNotes, and Rational Portfolio Manager, many of which used the Dojo Toolkit. He is an original contributor of dojox.mobile and a committer to the Dojo Toolkit.



19 November 2012

Also available in Chinese Portuguese

About this series

This series introduces the new functional features in Dojo Mobile 1.8. To get the most out of this series, you should be familiar with the Dojo Toolkit and its Asynchronous Module Definition (AMD) support.

This series doesn't cover Dojo Mobile features that are not new to version 1.8. Nor does it cover the non-functional enhancements, such as new device and OS version support; improvements to performance, accessibility, testability, and usability; and theme renewal. For details on all Dojo Mobile features, see the Resources later in this article.

Part 1 and Part 2 of this series show you many of the new widgets and widget enhancements in Dojo Mobile 1.8. This concluding article in the series shifts gears and introduces Dojo Mobile 1.8's new data-handler capabilities.

Item widgets such as ListItem and IconItem have a url property that you can use to load specified external view content to create a new target view dynamically. When the user selects the item widget, the new view is loaded and created. Until now, Dojo Mobile has supported only two data formats, HTML and JavaScript Object Notation (JSON), for the view content. It does this through two content handlers, one for HTML fragments and the other for JSON data.

Data handlers in Dojo Mobile 1.8 have been restructured to be customizable and extensible. In this article, learn about the components of this new structure and as well as the data handlers' data and control flows. You'll also see how to invoke data handlers programmatically. Then, with the help of sample code, you'll learn how to create and register a custom content handler.

Get Worklight now

Download IBM Worklight Developer Edition 5.0 now at no cost, and with no expiration date! Use the Worklight mobile app platform to develop and test the apps you build with Dojo Mobile.

A basic example

Listing 1 shows an example of opening two external views with the url property of ListItem:

Listing 1. Opening external views with the url property
<ul dojoType="dojox.mobile.RoundRectList">
  <li dojoType="dojox.mobile.ListItem" url="view1.html">
    Open External View (HTML)
  </li>
  <li dojoType="dojox.mobile.ListItem" url="view2.json">
    Open External View (JSON)
  </li>
</ul>

Listing 2 shows the external HTML content (view1.html) that's specified as the value of the first url property Listing 1:

Listing 2. External view content (view1.html)
<div id="view1" dojoType="dojox.mobile.View">
  <h1 dojoType="dojox.mobile.Heading" back="Home" moveTo="home">view1.html</h1>
  <ul dojoType="dojox.mobile.EdgeToEdgeList">
    <li dojoType="dojox.mobile.ListItem">
      Jack Coleman
    </li>
    <li dojoType="dojox.mobile.ListItem">
      James Evans
    </li>
    <li dojoType="dojox.mobile.ListItem">
      Jason Griffin
    </li>
  </ul>
</div>

Listing 3 shows the JSON content (view2.json) that's specified as the value of the second url property in Listing 1:

Listing 3. External view content (view2.json)
{
  "dojox.mobile.View": {
    "@id": "view2",
    "dojox.mobile.Heading": {
      "@back": "Home",
      "@moveTo": "home",
      "@label": "view2.json"
    },
    "dojox.mobile.EdgeToEdgeList": {
      "dojox.mobile.ListItem": [{
        "@label": "Jack Coleman"
      }, {
        "@label": "James Evans"
      }, {
        "@label": "Jason Griffin"
      }]
    }
  }
}

Figure 1 shows that the external HTML content from view1.html (Listing 2) opens when the user clicks the first ListItem created in Listing 1:

Figure 1. Dynamically loaded HTML content
Screenshot illustrating dynamically loaded HTML content

In Dojo Mobile 1.7 and earlier, the content handlers for HTML and JSON were hard-coded, leaving no room for customization. In Dojo Mobile 1.8, those handlers were refactored and separated out to be customizable.


Overall structure of data handlers

In Dojo Mobile 1.8, the data handlers are structured as shown in Figure 2. The dashed boxes represent abstract interfaces (because no real modules exist for abstract interfaces), and the gray boxes are the actual classes. They are called from ViewController, which controls view transitions.

Figure 2. Data-handler classes
Data-handler class structure in Dojo Mobile 1.8

As you can see in Figure 2, Dojo Mobile data handlers consist of five parts: DataHandler, FileTypeMap, DataSource, ContentTypeMap, and ContentHandler.

DataHandler

The DataHandler component provides an interface between content data and a ContentHandler. It fetches content data through DataSource and calls ContentHandler to parse the content data and create a new view.

FileTypeMap

FileTypeMap provides a map for determining content-type from the URL of the content data. Two actual modules are available: SuffixFileTypeMap and PatternFileTypeMap. SuffixFileTypeMap, which is the default module, determines content-type from a suffix of the given URL. PatternFileTypeMap determines content-type by pattern-matching against the given URL.

By default, SuffixFileTypeMap has the map shown in Listing 4:

Listing 4. Predefined map in SuffixFileTypeMap
{ // key: suffix, value: content-type
  "html": "html",
  "json": "json"
};

PatternFileTypeMap has the default map shown in Listing 5:

Listing 5. Predefined map in PatternFileTypeMap
{ // key: regexp, value: content-type
  ".*\.html": "html",
  ".*\.json": "json"
};

To register a new entry in the map, you can use the add() method, as shown in Listing 6:

Listing 6. Registering a content-type
require([
  "dojox/mobile/dh/SuffixFileTypeMap",
  ...,
], function(SuffixFileTypeMap){
  SuffixFileTypeMap.add("acme", "data"); // regard *.acme as "data" type
});

DataSource

DataSource encapsulates access to data. Two actual modules are available: UrlDataSource and StringDataSource. UrlDataSource, which is the default module, accesses the given URL and fetches the data as text. StringDataSource simply returns the given text.

ContentTypeMap

ContentTypeMap provides a map for determining content-handler class from a content-type. The dojox.mobile.dh.ContentTypeMap class is an actual singleton class. By default, it has the map shown in Listing 7:

Listing 7. Predefined map in ContentTypeMap
{ // key: content-type, value: content handler class name
  "html": "dojox/mobile/dh/HtmlContentHandler",
  "json": "dojox/mobile/dh/JsonContentHandler"
};

To register a new entry in the map, you can use the add() method, as shown in Listing 8:

Listing 8. Registering a content handler
require([
  "dojox/mobile/dh/ContentTypeMap",
  ...,
], function(ContentTypeMap){
  ContentTypeMap.add("html", "dojox/mobile/dh/MyHtmlContentHandler");
});

ContentHandler

ContentHandler is responsible for parsing the given data and creating a new view at the specified position. Three actual modules are available: HtmlContentHandler, HtmlScriptContentHandler, and JsonContentHandler. HtmlContentHandler handles HTML fragment content like that shown in Listing 2. In the HTML fragment, the top level must be a View widget or its subclass. HtmlScriptContentHandler also handles HTML fragments and has the ability to execute inline script code, as shown in the example in Listing 9:

Listing 9. External view content with inline script
<script>
    alert("hello");
</script>
<script src="foo.js"></script>
<div id="view1" dojoType="dojox.mobile.View">
  ...
</div>

Script blocks can be anywhere in the HTML fragment, because they are removed from the content before a new view is created.

JsonContentHandler handles JSON data content, as shown in Listing 3.


Data and control flows of data handlers

Figure 3 illustrates data and control flows of the Dojo Mobile data handlers, showing what happens if the user selects an item widget with url="view1.html":

Figure 3. Data and control flows of data handlers
Data and control flows of the Dojo Mobile data handlers
  1. Selecting an item widget initiates a view transition, for which ViewController is responsible. So ViewController gets the control. ViewController first gives the url property's value to FileTypeMap to ask what its content-type is. FileTypeMap determines content-type based on the given url. In the example case, FileTypeMap returns html as the content-type by looking at the suffix of the url property's value (view1.html).
  2. ViewController passes the content-type (html) to DataHandler.
  3. DataHandler gives the content-type (html) to ContentTypeMap to ask which ContentHandler to use. ContentTypeMap returns the class name of a ContentHandler correponding to the content-type. In the example case, ContentTypeMap returns dojox/mobile/dh/HtmlContentHandler as a ContentHandler class for html.
  4. DataHandler loads external view content (view1.html) through DataSource. DataSource is responsible for fetching data from an appropriate data source specified by the url property.
  5. DataHandler passes the fetched data to the parse() method of the ContentHandler determined by ContentTypeMap.
  6. ContentHandler is responsible for creating a new view from the given data. In the parse() method, a new view is created according to the given data, under the specified target node.
  7. After the new view is created, ViewController performs a view transition to the new view.

External views are created only the first time they are opened, because the views are cached in ViewController.


Opening an external view programmatically

As you've seen, selecting an item widget that has the url property initiates the data handlers to create an external view. In Dojo Mobile 1.8, you can also open external views programmatically, without using item widgets. To do so, you can first get an instance of ViewController, which is a singleton, and then use its openExternalView() method. The method's first parameter is a hash object that holds transition parameters, and its second parameter is a target DOM node under which a new view is created.

When the user presses a button, Listing 10 loads view1.html, creates a new view directly under the <body>, and performs a view transition to the new view with the slide animation:

Listing 10. Opening view1.html programmatically
require([
  "dojo/_base/window",
  "dojo/_base/Deferred",
  "dijit/registry",
  "dojox/mobile/ViewController",
  ...,
], function(win, Deferred, registry, ViewController){
  var vc = ViewController.getInstance();
  onBtn1Clicked = function(e){
    vc.openExternalView({url:"view1.html", transition:"slide"}, win.body());
  };
});

....

  <button data-dojo-type="dojox.mobile.Button"
          data-dojo-props='onClick:onBtn1Clicked'>Load view1</button>

Listing 11 loads view2.html and creates a new view but does not perform a transition, which can be useful when you want to prefetch external views for later use:

Listing 11. Loading view2.html without transition
  onBtn2Clicked = function(e){
    vc.openExternalView({url:"view2.html", noTransition:true}, win.body());
  };

Listing 12 loads view3.json, creates a new view directly under containerNode, and performs a view transition without animation:

Listing 12. Opening view3.json without animation effects
  onBtn3Clicked = function(e){
    vc.openExternalView({url:"view3.json"}, containerNode);
  };

Listing 13 loads view4.json, creates a new view, writes a console message, and performs a view transition without animation:

Listing 13. Opening view4.json with callback
  onBtn4Clicked = function(e){
    Deferred.when(vc.openExternalView({url:"view4.json"}, win.body()), function(){
      console.log("view4 is ready");
    });
  };

In Listing 13, the openExternalView() method returns a Deferred object that resolves when the external view is ready and a transition starts.


Creating a custom data handler

With Dojo Mobile 1.8, you can create views from external content in data formats other than HTML and JSON. In this section, I'll show you how to build an application that creates a view dynamically by using the example XML content in Listing 14:

Listing 14. Sample XML content (library.xml)
<?xml version="1.0" encoding="UTF-8"?>
<library>
  <book isbn="0-123-45678-1">
    <title>Processing XML with Dojo</title> 
    <author>Martin Parker</author> 
    <publisher>Best House</publisher> 
  </book>
  <book isbn="1-98765-43-2">
    <title>Total Solar Eclipse</title> 
    <author>Steven Young</author> 
    <publisher>Media</publisher> 
  </book>
  <book isbn="0-345-67890-X">
    <title>The History of Java Coffee</title> 
    <author>Marco Rodriguez</author> 
    <publisher>Best House</publisher> 
  </book>
</library>

The application loads the external XML content (library.xml), collects the book titles, and creates a new view as shown in Figure 4:

Figure 4. Sample application that loads external XML data
Screenshot of an application that loads external XML data dynamically

Creating a custom XML DataSource

The first step is to create a custom XML DataSource. If you want the XML content as text, you could use the default dojox.mobile.dh.UrlDataSource. But if you want it as XML DOM, you need a custom XML DataSource.

A DataSource module must take url as a constructor parameter, implement the getData() method, and use the text property to return the fetched data. Listing 15 shows an example of a custom XML DataSource:

Listing 15. Custom XML DataSource (MyXmlDataSource.js)
define([
  "dojo/_base/declare",
  "dojo/_base/lang",
  "dojo/_base/xhr"
], function(declare, lang, xhr){
  return declare("acme.MyXmlDataSource", null, {
    text: null,

    constructor: function(/*String*/ url){
      this._url = url;
    },

    getData: function(){
      return xhr.get({
        url: this._url,
        handleAs: "xml",
        load: lang.hitch(this, function(response){
          this.text = response;
        })
      });
    }
  });
});

Creating a custom XML content handler

Now that you can get the XML content as XML DOM through the custom XML DataSource, the next step is to create a custom XML ContentHandler. It traverses the given XML DOM and creates a new view.

A ContentHandler must implement the parse() method, which creates a new view with the given data (the first argument), under the given target node (the second argument). The third argument is a reference node. If you include it, the new view must be created directly before the reference node. The parse() method must return the ID of the created view. Listing 16 shows an example of a custom XML ContentHandler:

Listing 16. Custom XML content handler (MyXmlContentHandler.js)
define([
  "dojo/_base/declare",
  "dojo/dom-construct",
  "dojox/mobile/Heading",
  "dojox/mobile/View",
  "dojox/mobile/RoundRectCategory",
  "dojox/mobile/RoundRectList",
  "dojox/mobile/ListItem"
], function(declare, domConstruct, Heading, View,
      RoundRectCategory, RoundRectList, ListItem){

  return declare("acme.MyXmlContentHandler", null, {
    parse: function(xml, target, refNode){
      var container = domConstruct.create("div");
      target.insertBefore(container, refNode);

      var view = new View(null, container);

      var heading = new Heading({
        label: "My Books",
        back: "Home",
        moveTo: "home"
      });
      view.addChild(heading);

      var categ = new RoundRectCategory({
        label: "Title"
      });
      view.addChild(categ);

      var list = new RoundRectList();
      view.addChild(list);

      // finds <title> tags and generates items
      var nodes = xml.getElementsByTagName("title");
      for(var i = 0; i < nodes.length; i++){
        var item = new ListItem({
          label: nodes[i].firstChild.nodeValue
        });
        list.addChild(item);
      }

      view.startup();
      return view.id;
    }
  });
});

You are now ready to register a new content-type for XML and your custom content handler.

Registering a content-type

To register a new content-type, you can get a module return value of a FileTypeMap module and use the add() method, as shown in Listing 17:

Listing 17. Registering a content-type
require([
  "dojox/mobile/dh/SuffixFileTypeMap",
  ...
], function(SuffixFileTypeMap){
  SuffixFileTypeMap.add("xml", "xml"); // regard *.xml as "xml" type
});

In this example, the first argument of add() is a suffix to be matched. The second argument is the corresponding content-type.

Registering a content handler

To register a new content handler, you can get a module return value of the ContentTypeMap module and use the add() method, as shown in Listing 18:

Listing 18. Registering a content handler
require([
  "dojox/mobile/dh/ContentTypeMap",
  ...
], function(ContentTypeMap){
  ContentTypeMap.add("xml", "acme/MyXmlContentHandler");
});

In this example, the first argument of add() is a content-type, and the second argument is the corresponding content handler.

Specifying a custom DataSource

The final step is to specify a custom DataSource. You can do this by specifying dataSourceClass to an item widget through the transitionOptions property, as shown in Listing 19:

Listing 19. Specifying a custom DataSource
<li data-dojo-type="dojox.mobile.ListItem"
    data-dojo-props='url:"library.xml",
    transitionOptions:{dataSourceClass:"acme/MyXmlDataSource"}'>
  My Books
</li>

Listing 20 shows the sample application's HTML page:

Listing 20. Sample application's HTML page (sample.html)
  <script type="text/javascript">
    require([
      "dojox/mobile/dh/SuffixFileTypeMap",
      "dojox/mobile/dh/ContentTypeMap",
      "dojox/mobile/parser",
      "dojox/mobile",
      "dojox/mobile/compat"
    ], function(SuffixFileTypeMap, ContentTypeMap){
      SuffixFileTypeMap.add("xml", "xml"); // regard *.xml as "xml" type
      ContentTypeMap.add("xml", "acme/MyXmlContentHandler");
    });
  </script>
</head>
<body style="visibility:hidden;">
  <div id="home" data-dojo-type="dojox.mobile.View">
    <h1 data-dojo-type="dojox.mobile.Heading">Sample App</h1>
    <ul id="list" data-dojo-type="dojox.mobile.RoundRectList">
      <li data-dojo-type="dojox.mobile.ListItem"
          data-dojo-props='url:"library.xml",
          transitionOptions:{dataSourceClass:"acme/MyXmlDataSource"}'>
        My Books
      </li>
    </ul>
  </div>
</body>
</html>

Conclusion

In this article, you learned how the data handlers in Dojo Mobile 1.8 are structured, and how to use them both declaratively and programmatically. You also learned how to create and register a custom data handler. Take full advantage of this highly customizable and extensible data-handler mechanism to develop your dynamic mobile web applications.

Resources

Learn

Get products and technologies

  • Dojo 1.8.x: Download the latest Dojo Toolkit version.

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 Mobile development on developerWorks


  • Bluemix Developers Community

    Get samples, articles, product docs, and community resources to help build, deploy, and manage your cloud apps.

  • Mobile weekly

    Innovations in tools and technologies for mobile development.

  • DevOps Services

    Software development in the cloud. Register today to create a project.

  • IBM evaluation software

    Evaluate IBM software and solutions, and transform challenges into opportunities.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Mobile development
ArticleID=846442
ArticleTitle=What's new in Dojo Mobile 1.8, Part 3: Data-handler enhancements
publish-date=11192012