Back to my page

Developers


Building a Twitter widget, part 3: paging and automatic preferences

The first part of this series saw us build a widget that displayed a single Twitter status. The second part built upon the first on, and expanded the widget to display the whole public timeline feed, all the while learning UWA techniques and good practices.

Techniques and best practices are the central elements of the present third part: we will introduce paging, through the Pager control, and automatic preferences updates. Those two, once built into our widget, will immensely enhance its ease of use, and should be seen as best practices.

Twitter 03: paging

As usual, you can download and work with the previous version if you want to follow along.

Using the Pager control

Our previous version of the widget downloaded the public timeline feed, and let the user choose how many items to display. That imposed a limitation: if the user chose to display less than 20 items, he had no access to the remaining items: they were in effect hidden from view. This is why paging is much needed.

UWA provides a handful of controls, which are JavaScript objects that generate the proper HTML to use UWA templates (that is, CSS rules). Using templates and controls rather than one’s own recreation ensures that the widget is always well integrated into the user’s Netvibes theme.

The Pager control is available using the UWA.Controls.Pager object, which you have to set to a few data sources using a JSON object, like so:

Twitter.display = function(json) {
(...)
  var pager = new UWA.Controls.Pager(
    {
    module: widget,
    limit: widget.getValue('limit'),
    offset: widget.getValue('offset'),
    dataArray: json
    }
  );
}

module must be a reference to the widget. Most of the time, widget will suffice.
limit must be set to the number of displayed items. We here retrieve the content of our Range preference.
offset must be set to the number of the page itself (starting with zero). We here make use of a new, hidden preference, which acts as a global variable. We add right after the limit preference that we put in place in the previous version.

<preference name="offset" type="hidden" defaultValue="0" />

dataArray, at last, must be set to the array returned by the feed source. Here, that’s the json array, which we got from our Ajax request on the Twitter API method http://twitter.com/statuses/public_timeline.json.

In order to deal with page-changing, we then set an onChange event to the Pager object, and use to update the widget accordingly – for instance, setting the new value of the offset preference, and re-displaying the whole content based on that new offset:

pager.onChange = function(newOffset) {
  widget.setValue('offset', newOffset);
  Twitter.display();
}

Once all the JavaScript code is set up, we need to place a target div in the HTML code, where we want the paging to appear. Since our HTML is still dynamically generated using the setHTML method, we add that new element at the end of setHTML’s arguments in Twitter.display():

(...)
p.setHTML(
  (...)
  + ')<div class="paging"></div>'
)
widget.body.appendChild(p);
(...)

…and then properly put the generated paging in, at the end of Twitter.display

var pagerContainer = UWA.$element(
  widget.body.getElementsByClassName('paging')[0] );
pagerContainer.setContent( pager.getContent() );

In these last two lines, we use the UWA.$element() method, which extends any hand-created element with UWA’s DOM methods. Remember that elements created through the standard createElement() are already extended. We then call the pager’s getContent(), which will take in charge the generation of the whole pager HTML code.

The generated code gives you one or two bottom links, depending on where in the paging you are: ‘prev’ and ‘next’. Each link features an automatic onclick event, which calculates the newOffset value for the pager.onChange method: offset - limit for ‘prev’, offset + limit for ‘next’.

Once the new offset is set, the next line of our pager.onchange method triggers Twitter.display(), which creates the whole code around the JSON representation of the requested data – which was already downloaded. This is why it is useful to separate data downloading (in Twitter.onLoad) and data displaying (in Twitter.display): so that we can change the display without reloading the whole data every time.

Still, two last changes are necessary in order for our pager to work properly. First, change the loop that parses through our data feed. It was written this way:

for (var i = 0; i < json.length; i++ ) {

But since we take pages into account, we have to include our current offset in the equation. Therefore:

for (var i = widget.getValue('offset'); i < json.length; i++ ) {

Second and last change: since our offset is stored as a preference, it will saved for your next connection. This is not what we will want here, because that would imply that reloading the widget will directly get you to the previous offset, but with new content. So we have to reset it at each reloading, just in case:

Twitter.onLoad = function() {
  widget.setValue('offset', 0);
  widget.setTitle('Twitter public timeline');
  UWA.Data.getJson(
    'http://twitter.com/statuses/public_timeline.json',
    Twitter.display
  );
}

Paging is now working as expected.

Automatic preference update

By default, preferences do not impact the widget until the preference form is closed, using the ‘OK’ button or the ‘Close Edit’ text link. This can make preference-testing quite long for the user. You are therefore encouraged to add the onchange attribute to some of your preferences, making them point to a method that will redisplay the content according to the new setting. This is very quickly done.

First, add the onchange attribude, and make it point to a method:

<preference name="limit" type="range"
  label="Number of items to display" defaultValue="10"
  step="1" min="1" max="20" onchange="reParse" />

The method pointed by onchange will be called within the widget namespace. Therefore, you must define that method as widget.reParse.

You can make whatever you want of it: make it point directly to widget.onLoad, or having a real code block, like so:

widget.reParse = function() {
  if (Twitter.json) Twitter.display(Twitter.json);
  else widget.onLoad();
}

To make that if() line work properly, we just have to add a small line around the beginning of our Twitter.display method:

if (json) Twitter.json = json;

This will make our JSON data available to all the other methods.

And we’re now done with this thirs part of our series. Here is our new version of the widget. Check the code to fully understand the changes since the previous version.

Share this post:
  • E-mail this story to a friend!
  • Print this article!
  • Netvibes
  • Twitter
  • Facebook
  • Digg
  • Reddit
  • del.icio.us
  • blogmarks
  • description
  • Wikio

Tags: , , , , , , ,

Leave a Reply


Business

Partner with us.

Developers

Build once, run everywhere.

Community

Get involved, get localized.

Press

News. Media kits. Press releases.