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
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.)
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
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.
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;
}
});
});
|
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.
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
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)";
}
|
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
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
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
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
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";
}
|
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");
}
|
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.
| Description | Name | Size | Download method |
|---|---|---|---|
| PullView widget and sample apps | pullview.zip | 16KB | HTTP |
Information about download methods
Learn
- Dojo Mobile: Learn
more about Dojo Mobile features.
- Dojo Mobile documentation: Consult the Dojo Mobile Reference
Guide and API documentation.
-
Dojo Mobile
tutorials: Take advantage of these Dojo Toolkit 1.8
tutorials.
- Dojo Mobile 1.8 nightly build tests: See how Dojo Mobile 1.8
widgets work by trying out the nightly build tests.
- Dojo Mobile on developerWorks: Learn more about Dojo Mobile from
these developerWorks articles.
- Dojo Mobile Showcase: Use the showcase's slick UI to explore
loads of sample widgets.
- ToDo application: Play with a sample app that demonstrates
dojox/app, dojox/mobile, and dojox/mvc.
- Nightly
demos: Search the latest Dojo demos for more mobile demos (folder
names start with mobile).
- Mobile development resources on developerWorks: Find
how-to articles, evaluation code, and expert perspectives on a range of
topics for mobile developers.
Get products and technologies
- Dojo 1.8.x: Download the
latest Dojo Toolkit version.

Yoshiroh 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.




