Skip to main content

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

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

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.

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

All information submitted is secure.

  • Close [x]

Ajax -- A guide for the perplexed, Part 2: Develop a Dojo-based blog reader

Take a hands-on tour of Ajax development, the Dojo framework, and blogging

Gal Shachor, Senior Technical Staff Member, IBM
Gal Shachor is an IBM Senior Technical Staff Member and researcher working at the IBM Haifa Research Lab, on various topics related to middleware and rich Internet applications. Gal is the author of the book JSP Tag Libraries and several technical articles.
Ksenya Kveler (ksenya@il.ibm.com), Research Staff Member, IBM
Ksenya Kveler holds a B.Sc. in Computer Science from the Technion - Israel Institute of Technology. For the last five years, she has been working as a software engineer in the IBM Haifa Research Lab, mostly in the fields of distributed systems, simplified application development tools and, currently, medical informatics. Her main interests are Java and Web technologies.
Maya Barnea (mayab@il.ibm.com), Research Staff Member, IBM
Maya Barnea holds a B.Sc. in Mathematics and Computer Science from the Haifa University. For the last five years, she has been working as a software engineer in the IBM Haifa Research Lab, mostly in the fields of visual application development tools and complex event processing. Her main interests are Java and Web technologies, event processing, simplified programming, and usability.

Summary:  The previous installment of this series introduced you to Ajax development by walking through the practical information essential for getting an Ajax-enabled environment up and running. In this article, Part 2 of the series, the authors put your newly gained knowledge into practice by starting the development of a simple Dojo and Atom-based blog reader.

View more content in this series

Date:  11 Dec 2007
Level:  Intermediate
Also available in:   Chinese  Russian

Activity:  17347 views
Comments:  

The Atom protocol pair lets online providers of resources such as news, community Web sites, and blogs to syndicate their content through the Web. In a typical use of Atom, content providers syndicate a file, or a Web feed, and make it available over the Web. The feed, whose representation is defined in the Atom Syndication Format, provides a summary of recently added resources. Published feeds can then be used by Atom client software, such as blog readers, which leverage the Atom Publishing Protocol to discover newly added content and present it.

This article will add to your Ajax knowledge by demonstrating how to start to develop an Ajax- and Atom-based blog reader (in this installment you will develop the view and controller components of the reader). You'll use the Dojo toolkit to develop the application, which will communicate with back-end Atom feeds using the Atom Publishing Protocol. You'll also use the Dojo storage package to keep feed subscription data.

Dojo — our Ajax toolkit of choice

This blog reader application is based on the Dojo toolkit, and you might wonder why we selected Dojo and not some of the other toolkits out there. The Book of Dojo (see Resources) suggests several reasons, but for the purposes of this exercise, we cite two simple reasons that drove us to use Dojo:

  • Vertical integration and completeness: compared to other open source Ajax toolkits, Dojo offers the most complete and integrated library of components.
  • Black box reuse: the Dojo widget mechanism allows developers to compose new applications from widgets without knowing their internals. This makes it relatively easy to create sophisticated Ajax applications.

What's in this article?
Learn how to use the Dojo toolkit to develop an Ajax- and Atom-based blog reader. This part of the series will get you started with the essentials of blogging architecture and demonstrate how to implement the blog reader. The next article of the series will walk you through the actual implementation of the model.

Vertical integration and completeness

Dojo has a layered architecture, where each layer adds a progressively more advanced functionality:

  • The Dojo core layer includes the fundamental Ajax features that are present in many toolkits (such as IO and DnD), cross-browser compatibility, basic DOM manipulations, and so on.
  • On top of the Dojo core, the DIJIT layer provides the widget system as well as many widgets.
  • The last layer, DOJOX, includes various extensions such as offline storage and cross-browser vector graphics.

Collectively, the various layers of the Dojo architecture produce a comprehensive integrated toolkit that addresses most development needs.

Black Box reuse — widgets

Dojo widgets are Ajax-based UI components that can be reused with a single line of HTML code. For example, Listing 1 shows how an expandable title pane widget can be instantiated in an HTML page:


Listing 1. Title pane widget instantiation in an HTML page
                
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
	"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <script type="text/javascript" src="../../dojo/dojo.js" 
            djConfig="parseOnLoad: true, isDebug: true"></script>

    <script language="JavaScript" type="text/javascript">
            dojo.require("dijit.TitlePane");
            dojo.require("dojo.parser");		
    </script>

    <style type="text/css">
        @import "../../dojo/resources/dojo.css";
        @import "../themes/tundra/tundra.css";
    </style>
</head>
<body class="tundra">
    <div dojoType="dijit.TitlePane" 
        title="This is the title" style="width: 300px;">
        And this is the content, clicking the title 
        will expand/collapse me.
    </div>
</body>
</html>
        

As you can see, the page starts by importing the core Dojo library. Once the Dojo core is loaded, we can use dojo.require() to load the TitlePane widget, which we then reference inside the body tag.

Figure 1 shows the TitlePane widget in action, the outcome of the code fragment shown in Listing 1:


Figure 1. TitlePane widget in action
TitlePane widget in action

InformationBox — developing a simple Dojo widget

Widgets are implemented by a Dojo JavaScript class that provides the widget's functionality. For widgets with a complex UI, you can also provide an HTML fragment to function as the widget UI template. To dispel the magic behind widgets, let's develop a very simple widget that displays informational messages. The widget will allow users to title an information fragment and provide outcomes similar to the illustration in Figure 2:


Figure 2. InformationBox widget in action
Information Box widget in action

Listing 2 presents dwsample.Info, our informational message widget:


Listing 2. InformationBox widget implementation
                
if(!dojo._hasResource["dwsample.Info"]) {
    
    dojo._hasResource["dwsample.Info"] = true;
    dojo.provide("dwsample.Info");
    
    dojo.require("dijit._Widget");
    dojo.require("dijit._Templated");
    
    dojo.declare(
        "dwsample.Info",
        [dijit._Widget, dijit._Templated],
    {
        title: "",
    
        // The widget content template
        templateString: [
            "<div id='${id}' class='dijitTitlePaneTitle'>",
            "    <div>",
            "        <span dojoAttachPoint='titleNode' style='font-size:1.1em; margin: 
                       1em;'></span>",
    	    "    </div>",
    	    "    <div dojoAttachPoint='containerNode' class='dijitTitlePaneContent'></div>",
            "</div>"
        ].join('\n'),
    
        postCreate: function(){
            this.setTitle(this.title);
        },
    
        setTitle: function(/*String*/ title){
            this.titleNode.innerHTML = title;
        }
    });
}            
        

As shown in Listing 2, the widget implementation really starts with the dojo.declare() function. This function receives the widget's definition in JSON format and initializes a new widget.

An important aspect of this new widget is the templateString. It provides an HTML fragment that serves as a template to the HTML content generated by the widget. The template is scattered with dojoAttachPoint attributes instructing Dojo to attach the marked DOM element as a member of the generated template. This allows widgets direct access to the DOM nodes without DOM manipulations (as seen in the method setTitle). A special attach point, containerNode, signals a special DOM node where the widget body should be appended.

Using the new widget is simple, as demonstrated in Listing 3:


Listing 3. InformationBox widget usage
                
<div dojoType="dwsample.Info" 
     title="Do not panic, here is what you need to do" 
     style="width: 500px;">
    At first, developing a Dojo widget looks like a chore, but it is 
    not! Here is what you should do:
    <ol>
        <li>Create a JavaScript file with the name of the widget and in 
            a directory structure known by Dojo</li>
        <li>Extend the Dojo widget base classes</li>
        <li>...</li>
    </ol>
</div>
        

While the informational message is a very simple widget — it does not use events or expose new methods — it should give you enough of an idea of how widgets operate.

Now that you have a basic knowledge of Dojo, let's take a look at Atom and its use in our blog reader.


Atom and blogging

The term Atom refers to a pair of standards that define a feed format (for representing) and a protocol (for editing) Web resources such as Weblogs, online journals, Wikis, and similar content:

  • The Atom Syndication Format (ASF) was standardized in RFC 4287 and specifies the representation format of Atom resources.
  • The Atom Publishing Protocol (APP) is still in its draft form and specifies how to use REST to manage Atom resources.

Note that while Atom started with blogging in mind, it has a more general use in that it allows for CRUDing Web resources (CRUD is an acronym for create/read/update/delete).

The Atom Syndication Format (ASF)

The ASF specifies the XML representation for resources carrying information on syndicated item collections (also known as feeds) and the items they contain (known as entries):

  • A feed is a uniquely identified, titled, and time-stamped collection of syndicated resource entries. Blogs are normally represented by one or more feeds.
  • An entry is a uniquely identified, time-stamped resource with metadata such as title, summary, and categories. The entry's resource content can be anything from inline text to binary base64 encoded blob to out-of-line content specified by URI. Blog entries are normally represented by an entry in the blog feed.

To make the ASF more concrete, let's take a look at a short, single-entry Atom feed document in Listing 4:


Listing 4. Sample Atom feed
                
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

   <title>My Blog</title>
   <link href="http://example.org/myblog/"/>
   <updated>2005-11-13T16:25:05Z</updated>
   <author>
       <name>John Smith</name>
   </author>
   <id>urn:uuid:50a70c74-d399-11d9-b93C-0004545e0af6</id>

   <entry>
      <title>What is Atom?</title>
      <link rel="alternate" href="http://example.org/myblog/1"/>
      <id>urn:uuid:1234c670-cfb8-4ebb-aaaa-80da352efa6a</id>
      <updated>2005-11-13T16:25:05Z</updated>
      <summary> The term Atom refers to a pair of standards</summary>
      <content type="text/html"> 
            The term Atom refers to a pair of
            standards which are primarily used in the context of Web 
            content syndication. The emergence of Atom was motivated ...
      </content>
   </entry>
</feed>        
        

As you can see, the feed representation carries with it some feed-specific information, followed by any number of entries.

The Atom feed information includes a few mandatory elements as well as recommended and optional elements. The mandatory feed elements include:

  • Title: Provides a human-readable title for the feed. Typically, it is the same as the title of the associated Web site.
  • Updated: Indicates the most recent time when the feed was modified, in a format the publisher considers significant.
  • ID: Conveys a permanent, universally unique identifier for the feed.

The Link element, a recommended Atom feed element, can be used to link to various other resources that are related to the feed (including links back to the Atom feed resource).

The Atom entry element is similar to the feed element in that it also must contain the title, updated, and ID sub-elements. In reality, however, the entry does not serve its purpose without additional elements, such as:

  • Link: Links to a resource that is related to the entry. The relation type is defined by the rel attribute; for example, the value alternate signifies that the link provides an alternate representation of the resource described by the entry element.
  • Content: Contains either the actual resource representation or links to the representation.
  • Summary: Provides a short excerpt of the entry.

If no entry content is provided, there must be at least one alternate link pointing to the content.

Atom Publishing Protocol (APP)

The APP is a REST-based protocol for publishing and editing Web resources. This means that APP applies not only to Atom resources, but also to other Web-related resources, such as images, e-mail content, and more. As RESTful protocols go, APP leverages the HTTP protocol (including methods, headers, and status codes, among others) to CRUD the resources. APP will be used by your blog reader to interact with ATOM feeds and entries.

APP introduces the concept of collections, which are sets of resources that can be retrieved in whole or in part. In the Atom syndication realm, these collections and resources are mapped to Atom feed and entry resources, whose representation is encoded according to the ASF. In addition to collections and resources, the APP also defines workspaces and services that can be used to discover collections (however, this is beyond the scope of this article).

Now, having covered plenty of background, you're ready to start building your blog reader!


Implementing a blog reader with Atom

Our blog reader application (shown in Figure 3) manages a list of blog feeds (and their URIs) which are of interest to the user:


Figure 3. Blog reader application
Blog reader application

Feeds can be added to and removed from the list. In our application, users subscribe to a specific feed of interest by entering its title and URI into the dialog box (as shown in Figure 4):


Figure 4. Adding a feed
Adding a feed

When a user wants to see content in a certain feed, he or she simply selects it in the feeds combo-box. Behind the scenes, the blog reader application follows the APP and sends an HTTP GET request to the feed URI. The reader then checks the returned HTTP status code and in case of success (status code is 200), it retrieves the resulted Atom entry collection from the HTTP response payload. At this point, the reader inspects the returned entries and presents them to the user. First, the entries are listed together at the left side of the application, with the entry title representing the entry in the list (see Figure 5):


Figure 5. Listing the entries
Listing the entries

At this point, the user can select an entry from the list by clicking it and the reader does its best to present the content of the entry using the following algorithm:

  1. If the entry includes a content element with actual resource representation, it is used.
  2. Otherwise, if a summary element is available, it is used.
  3. If both content and summary elements are missing, a link to the content is presented. If the original article link could not be detected either, the link to the alternate entry resource representation is given, as specified in the link element with rel attribute having alternate value. When the user follows the link, a new browser window is opened with the link.

The reader application follows the model view control (MVC) design pattern. Upcoming sections cover the implementation of the reader view and control components. (The model and the technology used for implementation will be covered in a future article.) Note that in our MVC implementation, a practical approach was taken that preferred simplicity over design purity. Therefore, the view and control are coupled more than may be optimal.


The View component

The blog reader view is implemented as a single HTML file that leverages Dojo. The view includes three main sections as sketched in the (skeletal) Listing 5:


Listing 5. View component implementation
                
<html>
    <head>
     <!-- Section 1, Dojo and application imports -->
    </head>
    
    <body class="tundra">
        <!-- Section 2, Blog Reader UI -->
        <fieldset class="feed-definition-area">
            Select Feed:
             ...
        </fieldset>
        <hr>
        <div class="feed-area">
            <div dojoType="dijit.layout.SplitContainer"
             ...
            </div>
        </div>		

        <!-- Section 3, dialog box definitions -->
        
        <div dojoType="dijit.Dialog" 
            id="add-feed-dlg" 
            ...
        </div>

        <!-- Progress dialog -->
        <div dojoType="dijit.Dialog" 
            id="progress-dlg"
            title="">
            ...
        </div>
        
        <div dojoType="dijit.Dialog" 
            id="error-msg-dlg"
            ...
        </div>
    </body>
</html>
        

  1. The first section imports the various JavaScript, CSS, and widgets used throughout the application.
  2. The second section constructs the main reader UI.
  3. The third section defines all the various dialog boxes used throughout the reader implementation.

Let's take a more detailed look into the various sections of the application.

Section 1: Imports

Take a look at Listing 6, which presents the full Imports section of the application:


Listing 6. Imports section
                
<head>
    <title>Blog Reader</title>

    <script type="text/javascript" 
            src="./reset-styles.js"></script>		

    <style type="text/css">
        @import "../dojoAjax/dojo/resources/dojo.css";
        @import "../dojoAjax/dijit/themes/tundra/tundra.css";
        @import "css/blogreader.css";
    </style>
        
    <script type="text/javascript" 
            src="../dojoAjax/dojo/dojo.js"
            djConfig="parseOnLoad: true"></script>

    <script type="text/javascript">
        dojo.require("dijit.Dialog");
        dojo.require("dijit.util.manager");
        dojo.require("dijit.form.Button");
        dojo.require("dijit.form.Textbox");
        dojo.require("dijit.layout.SplitContainer");
        dojo.require("dijit.layout.ContentPane");
        dojo.require("dojo.parser");
    </script>

    <script type="text/javascript" src="blog-reader.js"></script>	
	
</head>            
        

The Imports section starts by importing the JavaScript file reset-styles.js, which resets the CSS properties of the various tags to well-known defaults. Following the style reset, the various CSS files that set the look and feel of the application are imported. We first import the Dojo CSS files (and especially tundra.css that sets the look and feel of the various Dojo widgets) and then add to them several blog reader-specific styles.

The next step is to import the Dojo library. In this case, Dojo is located in the dojoAjax directory and the core dojo.js is imported. The various required Dojo widgets are also imported using the dojo.require() method (provided by the Dojo core).

As a last step, the blog reader logic held inside the file blog-reader.js is imported (you will explore blog-reader.js later in this article).

Section 2: Reader UI construction

Now that the various CSS and JavaScript files are included, we can start building the application using HTML tags and Dojo widgets, shown in Listing 7:


Listing 7. Blog reader UI implementation
                
<body class="tundra">
      <fieldset class="feed-definition-area">
          Select Feed:
        <select dojoType="blogreader.FeedsCombo" id="feed-combo" comboClass="feedsCombo">
        </select>
        <button dojoType="dijit.form.Button" id="add-feed-btn" iconClass="addIcon">
            Add Feed
        </button>                                         
        <button dojoType="dijit.form.Button" id="clear-feed-btn" iconClass="cancelIcon">
            Clean Feeds
        </button>                                         
    </fieldset>
    <hr>
    <div class="feed-area">
        <div dojoType="dijit.layout.SplitContainer"
                orientation="horizontal"
                sizerWidth="7"
                activeSizing="false"
                class="article-splitter">
                <div dojoType="dijit.layout.ContentPane" 
                    sizeShare="30" 
                    sizeMin="20" 
                    style="overflow:auto">
                        <div id="articles-table-wrapper" 
                            style="visibility: hidden; width:96%">
                                <div dojoType="blogreader.ArticleList" 
                                id="article-list" 
                                listClass="articles-list" 
                                titleClass="articles-list-title"></div>
                        </div>
                </div>
        </div>
        <div dojoType="dijit.layout.ContentPane" 
             sizeShare="70"
             style="overflow:auto">
                <div id="article-content-pane" class="article-content-pane">
                    <div id="article-title-id" class="article-title">
                    </div>
                    <div id="article-content" class="article-content">
                    </div>
                </div>
        </div>
    </div>
        

The first noticeable Dojo dependency in this section is the use of the tundra class inside the body. Dojo implements visual themes using CSS. Setting the body class to tundra kicks in the use of the Dojo tundra theme.

The first UI element we create is the feed selection control located at the top-most portion of the application's UI. The feed selection control is created by assembling together an HTML select control and two Dojo buttons. A few things to note in this section:

  • We implemented a Dojo widget to wrap the select control. Wrapping the select with our own widget allows us to put all the presentation logic related to the feed selection (adding and removing feeds) in a single place.
  • We do not set callbacks from the view to the controller directly in the markup. Later on we will bind the controller JavaScript methods and control event handlers programmatically.
  • We decorate the buttons with icons (determined from a CSS class).

Next we construct the main area where the selected feed is presented. The goals for the feed presentation area are:

  • If a feed is selected, present a list of entries at the left.
  • If a certain entry is clicked, present its contents at the right. However, if the user did not select an entry, do not present anything.

We implement these goals using the Dojo split container, which allows us to take over the browser space and split it into two areas, each populated by ContentPane. The ContentPanes are separated by a sizer control that allows users to resize the ContentPanes. Each of the ContentPanes contains a div HTML element that wraps the content (entry list/entry content). Using these div elements, we can easily show and hide their content (using the display CSS style).

The entry list is once again implemented as a home-grown Dojo widget.

Section 3: Dialog boxes

The third and last view section instantiates the dialog boxes used within the reader. In a perfect world, each of the dialog boxes would have been implemented as a widget. However, to keep things short, we embed the dialog boxes into our main UI and handle their events in the controller.

Take a look at Figure 6, which presents the Add Feed dialog box, which is the most complex of the various dialog boxes:


Figure 6. Add Feed dialog box
Add Feed dialog box

Listing 8 presents the implementation of the Add Feed dialog box:


Listing 8. Add Feed dialog box implementation
                
<div dojoType="dijit.Dialog" 
    id="add-feed-dlg" 
    title="Add Feed"
    closeNode="cancel-add-feed-btn"
    style="width: 400px;">
    <form onsubmit="return false;"> 
        <table class="table-no-border">
            <tr>
                <td>
                    <label for="feed-name">Title: </label>
                </td>
                <td width="100%">
                    <div dojoType="dijit.form.TextBox"
                        id="feed-name" 
                        type="text"
                        required="true"
                        value=""
                        trim="true"
                        autocomplete="on"
                        classPrefix="noColors"
                        class="text-box"></div>
                </td>
            </tr>
            <tr>
                <td>
                    <label for="feed-url">URL: </label>
                </td>
                <td width="100%">
                    <div dojoType="dijit.form.TextBox"
                            id="feed-url" 
                            type="test"
                            required="true"
                            value=""
                            trim="true"
                            classPrefix="noColors"
                            class="text-box"></div>
                </td>
            </tr>
        </table>
        <fieldset>
            <button dojoType="dijit.form.Button" id="ok-add-feed-btn">
                OK
            </button>                                         
            <button dojoType="dijit.form.Button" id="cancel-add-feed-btn">
                Cancel
            </button>                                         
        </fieldset>
    </form>
</div>
        

An interesting thing to note about the Add Feed dialog box is how easy it is to implement it out of widgets and HTML markup, as follows:

  • By using the dijit.Dialog widget, we immediately gain the ability to open a simple and lightweight dialog box in the context of the existing browser window.
  • By populating dijit.Dialog with HTML markup and widgets, we determine how the body of the dialog box is going to look.
  • The cancel action can be easily implemented by using the closeNode attribute. This way, we do not need to implement the handler to the Cancel button.
  • The rest of the implementation is delegated to Dojo, which provides APIs that let us show and hide the dialog box including its content.

The Controller component

Our blog reader controller listens to events flowing from the view components and reacts to them by operating on the model. In general, the UI events are:

  • New feed selection: The controller needs to load and present the newly selected feed.
  • New entry selection: The controller needs to present the newly selected entry.
  • Add feed button activation: The controller needs to pop up the Add Feed dialog box.
  • Clean feeds button activation: The controller needs to erase the feed list.
  • The OK button was pressed in the Add Feed dialog box: The controller should take the entered title and URL and add a feed using them.

The controller interaction with the model has an interesting twist to developers new to Ajax — it is asynchronous. In general, the JavaScript code running inside the browser is single threaded. This means that if you want to keep the UI alive and responsive while the model communicates over the network, you should work in asynchronous mode. For this reason, the controller also listens to the following model events:

  • feedDataArrived: Fired by the model when it is done reading a feed. Upon receiving this event, the controller knows that the feed data is cached in the model object and can be presented in the view.
  • feedReadFailed: Fired by the model when the communication fails. Upon receiving this event, the controller knows that the model failed to communicate with the ATOM feed and an error message needs to be displayed

The upcoming sections walk you through the controller implementation and show how to connect to the view components and respond to various events using Dojo.

Binding to the UI and Model components

Listing 9 shows the general structure of the controller and focuses on the initialize() method and the two tasks it performs:

  • Locating the UI components through their IDs
  • Assigning listeners to various events in the model and the UI


Listing 9. Binding to the UI and Model components
                
var BlogController = {
    mHideProgressFunction: null,
    mFeedsCombo:           null,
    mAddFeedDlg:           null,
    mFeedURLTextbox:       null,
    mFeedTitleTextbox:     null,
    mArticleWrapper:       null,
    mProgressDlg:          null,
    mProgressDlgMsg:       null,
    mContentDiv:           null,
    mContentTitle:         null,
    mContentPane:          null,
    mErrDlgContent:        null,
    mErrDlg:               null,
    mArticleList:          null,
            
    // Initialize the page					
    initialize: function() {
        this.mFeedsCombo       = dijit.byId("feed-combo");
        this.mArticleList      = dijit.byId("article-list");
        this.mAddFeedDlg       = dijit.byId("add-feed-dlg");
        this.mFeedURLTextbox   = dijit.byId("feed-url");
        this.mFeedTitleTextbox = dijit.byId("feed-name"); 
        this.mArticleWrapper   = dojo.byId("articles-table-wrapper");
        this.mProgressDlg      = dijit.byId("progress-dlg");
        this.mProgressDlgMsg   = dojo.byId("progress-msg");
        this.mContentDiv       = dojo.byId("article-content");
        this.mContentTitle     = dojo.byId("article-title-id");
        this.mContentPane      = dojo.byId("article-content-pane");
        this.mErrDlgContent    = dojo.byId("error-msg-content");
        this.mErrDlg           = dijit.byId("error-msg-dlg");
        
        dojo.connect(BlogModel, 
                     "feedDataArrived", 
                     this, 
                     this.feedDataArrived);
    
        dojo.connect(BlogModel, 
                     "feedReadFailed", 
                     this, 
                     function(errMsg) {
                         this.hideProgressDlg();
                         this.cleanFeedUI();
                         this.showErrorMsgDlg(errMsg);
                         this.mFeedsCombo.setValue("");
                         this.mArticleWrapper.style.visibility = "hidden";
                     });

        BlogModel.initialize(this);

        this.populateFeedsCombo();
        
        // connect add feed/clean feeds to functions
        dojo.connect(dojo.byId("add-feed-btn"), 
                     "onclick", 
                     this, 
                     function() {
                         this.mAddFeedDlg.show();
                         this.mFeedTitleTextbox.focus();
                     });
        dojo.connect(dojo.byId("clear-feed-btn"), 
                     "onclick", 
                     this, 
                     this.cleanFeeds);
                     
        // dialog box callbacks             
        dojo.connect(dojo.byId("ok-add-feed-btn"), 
                     "onclick", 
                     this, 
                     this.createFeed);
                     
        // Listen to combo box selection changes             
        dojo.connect(this.mFeedsCombo, 
                     "onSelectionChanged", 
                     this, 
                     function() {		                 
                         this.readFeed(this.mFeedsCombo.getSelectedValue());
                     });
                     
        // List selection changes             
        dojo.connect(this.mArticleList, 
                     "onSelectionChanged", 
                     this, 
                     this.updateArticleContent);
    },

    createFeed: function(event) {
    	// Create a new feed reference, add it to the model and 
    	// to the feeds combo
    },

    cleanFeeds: function() {
	// erase all feed references from both the model and the view
    },
            
    // Updates the page content according the feed xml
    feedDataArrived: function() {
	// Feed was read. Update the reader with the new information
    },	
            
    updateArticleContent: function() {
	// The selection in the articles list changed, update the article pane
    },

    // Utility methods

    populateFeedsCombo: function() {
        // Populate the feeds combo box with the feeds registered in the model
    },

    readFeed: function(url) {
        // Cleans the feed presentation UI and initiates fetching a new feed
    },
    
    // Clean feed content
    cleanFeedUI: function() {
        // Zero the Feed presentation UI
    },

    showErrorMsgDlg: function(errorMsgContent) {
        // Pops up an error dialog box with a specific message
    },
    
    showProgressDlg: function(msg) {
        // Pops up the progress dialog box with a specific message
    }
};
        

The initialize() method shows how Dojo programs locate and reference UI components (HTML elements and widgets) using their component IDs and two methods:

  • dojo.byId(id): Looks up an HTML element using its ID as a parameter. The method returns the DOM object.
  • dijit.byId(id): Looks up a Dojo widget using its ID as a parameter. The method returns the JavaScript object instance representing the widget.

If you follow our use of the byId() methods in the controller, you will notice that we use them in the initialize() method and cache the returned results in member variables. This is not just for performance reasons, but more for maintainability. The IDs used in the view can change frequently during the development phase, so looking them up once (and in a well-known location) makes it easier to maintain the code.

Our controller uses dojo.connect to listen to events in the view and the model. dojo.connect allows Dojo applications to attach functions to method invocations in other objects. For example, the following code fragment attaches the function foo to the method bar in the object obj:


Listing 10. Listening to events
                
dojo.connect(obj, "bar", expectedThis, foo);

The third parameter of dojo.connect is the object reference to be used as this in the called method. This can turn out to be useful if you want to use a template function on different objects.

Note that because JavaScript treats functions as data, it is possible to pass function objects as parameters without declaring them specifically, as presented in the following code fragment:


Listing 11. Attaching function object
                
dojo.connect(this.mFeedsCombo, 
             "onSelectionChanged", 
             this, 
             function() {		                 
                 this.readFeed(this.mFeedsCombo.getSelectedValue());
             });

This feature comes in handy if you have many short functions (say, 2 - 3 lines) that are not used by anything but the connect method. In such a case, declaring the function at its place of use lets you improve the readability of your code.

Calling back on the Dojo widgets

As seen before, the Dojo widgets drive controller using events. However, how can the event handlers call back on the Dojo widgets? The answer is simple: Dojo widgets are simply JavaScript objects with public methods, and all you need to do is call these methods. Similarly, HTML elements and their attributes get exposed as DOM objects. As a result, the function showProgressDlg(msg) presented in the following code fragment can easily set a message into the progress dialog box and pop it up:


Listing 12. Event handler calling back on the Dojo widgets
                
initialize: function() {
    // setup references to Dojo widgets and DOM elements 
    this.mProgressDlg      = dijit.byId("progress-dlg");
    this.mProgressDlgMsg   = dojo.byId("progress-msg");
...
}
...
showProgressDlg: function(msg) {
    // Use the methods exposed by DOM and the widget
    this.mProgressDlgMsg.innerHTML = msg;
    this.mProgressDlg.show();
},
...
        

(For more information about the methods exposed by Dojo and DOM objects, refer to the DOM and Dojo references listed in the Resources section).

The developerWorks Ajax resource center
Check out the Ajax resource center, your one-stop shop for free tools, code, and information on developing Ajax applications. The active Ajax community forum, hosted by Ajax expert Jack Herrington, will connect you with peers who might just have the answers you're looking for right now.

Getting initialized

At this point, you want to initialize the controller when the page finishes loading and the Dojo widgets are ready for interaction. In this blog reader case, this means calling to BlogController.initialize. Dojo helps you accomplish the initialization tasks by providing a simple on-load hook mechanism through dojo.addOnLoad. For example, in our controller example, we are using the following code fragment to kickstart BlogController.initialize:


Listing 13. Controller initialization
                
dojo.addOnLoad(BlogController, BlogController.initialize);

dojo.addOnLoad can accept either one or two parameters:

  • When a single parameter is used, Dojo expects it to be the function to execute when Dojo is loaded.
  • With two parameters, it is expecting the first parameter to serve as this and the second parameter to be the function to execute when Dojo is loaded.

Note that as a developer, you can also try other approaches. For example, you could use dojo.connect and bind to one of the dojo object life cycle methods in a manner similar to the following code fragment. (However, note that this approach is not recommended because the life cycle methods can change in the future):


Listing 14. Another way for Controller initialization
                
dojo.connect(dojo, 
             "loaded", 
             BlogController, 
             BlogController.initialize);

Conclusion

You have learned about the essentials of blogging architecture and looked at two Atom standards and how they can be exploited by blog reader applications. You examined how the view and controller of a simple, yet functioning, Dojo-based reader can be implemented. The next article of the series will walk you through the implementation of the model. Stay tuned!



Download

DescriptionNameSizeDownload method
Sample blog applicationwa-aj-basics2.zip18KB HTTP

Information about download methods


Resources

About the authors

Gal Shachor is an IBM Senior Technical Staff Member and researcher working at the IBM Haifa Research Lab, on various topics related to middleware and rich Internet applications. Gal is the author of the book JSP Tag Libraries and several technical articles.

Ksenya Kveler holds a B.Sc. in Computer Science from the Technion - Israel Institute of Technology. For the last five years, she has been working as a software engineer in the IBM Haifa Research Lab, mostly in the fields of distributed systems, simplified application development tools and, currently, medical informatics. Her main interests are Java and Web technologies.

Maya Barnea holds a B.Sc. in Mathematics and Computer Science from the Haifa University. For the last five years, she has been working as a software engineer in the IBM Haifa Research Lab, mostly in the fields of visual application development tools and complex event processing. Her main interests are Java and Web technologies, event processing, simplified programming, and usability.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


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. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

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.

(Must be between 3 – 31 characters.)

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

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development, XML
ArticleID=275798
ArticleTitle=Ajax -- A guide for the perplexed, Part 2: Develop a Dojo-based blog reader
publish-date=12112007
author1-email=shachor@il.ibm.com
author1-email-cc=
author2-email=ksenya@il.ibm.com
author2-email-cc=ruterbo@us.ibm.com
author3-email=mayab@il.ibm.com
author3-email-cc=ruterbo@us.ibm.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers