Pull down to refresh with Dojo Mobile

Implement a popular UI pattern used in native smartphone apps, and adding some more wordy words here to test Acrolinx27

Learn how to use Dojo Mobile 1.8 to implement the popular pull-down-to-refresh feature in your mobile web applications. This article show you how to build two sample applications: a pull-down-to-refresh app and a pull-down-to-go-back variant. Full downloadable source code is provided. After working through the examples, you'll be able to implement many more variations on this UI pattern.

Share:

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.



13 November 2012

Also available in Japanese Portuguese Spanish

Pull down to refresh is a widely used UI pattern in native smartphone applications for iPhone, Android, and BlackBerry. It does exactly what the name indicates: If you navigate to the top of a list, pull it down, and release it, the list refreshes its contents. This popular feature, shown in action in Figure 1, gives users quick way to refresh the view:

Figure 1. Pull down to refresh
Three screenshots demonstrating the pull down to refresh feature in an iOS application

This article shows you how to implement the pull-down-to-refresh feature in your apps with Dojo Mobile 1.8. Start by creating a small widget that enables users to pull down the view to reveal a message box at the top. Then use that widget to build two sample applications: a pull-down-to-refresh application and a pull-down-to-go-back application. (Get the complete source code in the Download section at the end of this article.)

Create the PullView widget

As you can see in Figure 1 and in the native smartphone apps that you use, a message box (an area that displays messages such as Pull down to refresh... ) and a list component move together when you pull down the list, while a header at the top has a fixed position. Listing 1 shows one way to achieve this behavior using Dojo Mobile:

Listing 1. Placing a message box in a ScrollableView
<h1 data-dojo-type="dojox.mobile.Heading"
    data-dojo-props='fixed:"top"'>Technical Topics</h1>
<div id="view1" data-dojo-type="dojox.mobile.ScrollableView">
  <div id="pull">
    <img id="icon" src="images/refresh-arrow.png">
    <div id="msg1">Pull down to refresh...</div>
    <div id="msg2">Check for new items</div>
  </div>
  <ul data-dojo-type="dojox.mobile.EdgeToEdgeDataList">
    ....
  </ul>
</div>

Listing 1 uses a Heading widget to place the header at the top. The message box and the list are in a ScrollableView widget. This way, the message box and the list scroll together, while the header is fixed. The message box, however, is visible from the outset, as shown in Figure 2:

Figure 2. Message box in a ScrollableView
Screenshot of a message box in a ScrollableView

You don't want the message box to appear until the user pulls down the list, so you need a way to hide it initially.

Hiding the message box

You can hide the message box by applying CSS that changes its position, as shown in Listing 2:

Listing 2. Hiding the message box at the top of the list
#pull {
  position: absolute;
  height: 65px;
  top: -65px;
}

Listing 2 hides the message box by giving it an absolute position that's above the list. When the user pulls the list down, the message box comes into view.

Keeping the message box visible

Now the message box is shown only when the list is pulled down. So far, so good. The problem, however, is that the ScrollableView bounces back to the initial position as soon as the user releases the list. Instead, you want to keep the message box visible while the list updates. To achieve this effect, you need to subclass ScrollableView and implement the necessary logic. The adjustDestination() method is a good place to do so. You can get the height of the message box and slide to the position where the entire message box is shown at the top. If adjustDestination() returns false, the default scrolling behavior is canceled. Listing 3 shows example code for the subclass:

Listing 3. Keep showing the message box (PullView.js)
define([
  "dojo/_base/declare",
  "dojo/dom",
  "./ScrollableView"
], function(declare, dom, ScrollableView){
  return declare("dojox.mobile.PullView", ScrollableView, {
    adjustDestination: function(to, pos, dim){
      var h = dom.byId("pull").offsetHeight;
      if(this.getPos().y >= h){ // if completely revealed
        this.slideTo({y:h}, 0.3, "ease-out");
        return false;
      }
      return true;
    }
  });
});

Publishing events

Finally, you need to publish events so that user application can listen to or connect to them, as shown in Listing 4:

Listing 4. Publishing events (PullView.js)
  return declare("dojox.mobile.PullView", ScrollableView, {
    adjustDestination: function(to, pos, dim){
      var h = dom.byId("pull").offsetHeight;
      if(this.getPos().y >= h){
        this.slideTo({y:h}, 0.3, "ease-out");
        connect.publish("/dojox/mobile/onPulled", [this]);
        this.onPulled(this);
        return false;
      }
      return true;
    },


    scrollTo: function(/*Object*/to, /*Boolean?*/doNotMoveScrollBar, /*DomNode?*/node){
      this.inherited(arguments); // scrollable#scrollTo() will be called
      var h = dom.byId("pull").offsetHeight;
      connect.publish("/dojox/mobile/onPull", [this, to.y, h]);
      this.onPull(this, to.y, h);
    },

    onPull: function(/*Widget*/view, /*Number*/y, /*Number*/h){
    },

    onPulled: function(/*Widget*/view){
    }
  });

In Listing 4, onPull() is called while the message box is being pulled. onPulled() is called when the message box is entirely pulled down and then released.


Build a pull-down-to-refresh app

Now that you have the PullView widget, you're ready to build a sample pull-down-to-refresh application. The first step is to rewrite Listing 1 as Listing 5:

Listing 5. Pull-down-to-refresh sample application
<h1 data-dojo-type="dojox.mobile.Heading"
    data-dojo-props='fixed:"top"'>Technical Topics</h1>
<div id="view1" data-dojo-type="dojox.mobile.PullView"
    data-dojo-props='onPull:onPull, onPulled:onPulled'>
  <div id="pull">
    <div id="prog" class="progDiv"></div>
    <img id="icon" src="images/refresh-arrow.png">
    <div id="msg1"></div>
    <div id="msg2">Check for new items</div>
  </div>
  <ul data-dojo-type="dojox.mobile.EdgeToEdgeDataList">
    ....
  </ul>
</div>

Next, you need to do few more things on the application side.

Rotating an arrow icon

You might want to rotate the arrow icon while the list is pulled down, as shown in Figure 3:

Figure 3. Rotating the icon while pulling down
Screenshot showing a rotating arrow icon in the message box, next to the message

As Listing 6 shows, you can rotate the arrow in the onPull() handler. You can also update the message in onPull() to tell the user to release the list.

Listing 6. Rotating an arrow icon
onPull = function(view, y, h){
  dom.byId("msg1").innerHTML = percent < 100 ?
    "Pull down to refresh..." : "Release to refresh...";
  y = y > h ? h : y;
  var percent = y / h * 100;
  var deg = -1.8 * percent + 360;
  dom.byId("icon").style.webkitTransform = "rotate(" + deg + "deg)";
}

Performing an action

The onPulled() handler is called when the message box is entirely pulled down and then released. You can place a refresh action into this handler. The action can vary, depending on the particular application. In Listing 7, the list widget refreshes its content by calling setStore():

Listing 7. Rotate an arrow icon
onPulled = function(view){
  if(prog1.timer){ return; }

  // hide the arrow icon
  dom.byId("icon").style.visibility = "hidden";

  // update the message
  dom.byId("msg1").innerHTML = "Loading...";

  // add a ProgressIndicator and start it
  dom.byId("prog").appendChild(prog1.domNode);
  prog1.start();

  // reload the datastore
  store.close();
  registry.byId("list").setStore(store);
}

Listing 7 also hides the arrow icon, updates the message to Loading..., and adds a ProgressIndicator. Figure 4 shows the content being refreshed:

Figure 4. Refreshing the content
Screenshot of list content being refreshed

Closing the message box

When the refresh action is completed, you close the message box as shown in Listing 8:

Listing 8. Closing the message box
connect.connect(registry.byId("list"), "onComplete", function(){
    registry.byId("view1").slideTo({y:0}, 0.3, "ease-out");
    prog1.stop();
    dom.byId("icon").style.visibility = "visible";
});

Figure 5 shows the list with the message box closed and the content updated:

Figure 5. Message box closed
Screenshot of the list view with the message box closed and the list content updated

Build a pull-down-to-go-back app

Now create a variation of the sample application — this time, a pull-down-to-go-back app. If the user pulls down the content, a green knob appears inside a horizontal slot and moves from right to left, as you can see in Figure 6:

Figure 6. Pull-down-to-go-back application
Two-part screenshot of the pull-down-to-go-back application. The left side shows the user pulling down on the content. The right side shows that a knob in a horizontal slot appears as the content is being pulled down.

If the user releases the content after the green knob reaches the slot's left edge, as shown in Figure 7, the application goes back to the previous view:

Figure 7. Ready to go back
Screenshot of the pull-down-to-go-back application showing that when the knob reaches the left edge of the slot, the user can go back by releasing the content.

Sliding a green knob

Just as you implemented rotation of the arrow icon in the first sample application with the onPull() handler, you can slide the knob node in onPull(), as shown in Listing 9:

Listing 9. Sliding a green knob
onPull = function(view, y, h){
  dom.byId("msg1").innerHTML = y < h ? "Pull down to go back" : "Go back";
  y = y > h ? h : y;
  var percent = Math.round(y / h * 100);
  dom.byId("knob").style.left = (100 - percent) + "px";
}

Performing an action

This time, the action you perform in the onPulled() handler is to go back to the previous view using the performTransition() method of the current view, as shown in Listing 10:

Listing 10. Going back to the previous view
onPulled = function(view){
  registry.byId("view2").performTransition("view1", -1, "slide");
}

Conclusion

In this article, you learned how to implement two variants of the pull-down-to-refresh UI pattern with Dojo Mobile 1.8. Now you should also be able to implement other pull-down-to-X applications, where X is the action of your choosing.

Note that the actual implementation of the PullView widget in the code sample is a bit more complex than what I've described in this article. It can even put the message box at the bottom of the view if you specify the pullDir="up" option. That option enables you to create a pull-up-to-load-more application, for example.


Download

DescriptionNameSize
PullView widget and sample appspullview.zip16KB

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


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Mobile development
ArticleID=845290
ArticleTitle=Pull down to refresh with Dojo Mobile
publish-date=11132012