Products
Technologies

Developer resources
Avg. Rating 3.8

Problem

I need pagination on a data set so I can eliminate the need for scrollbars. For my given data set, I only want to display a small set of items on the screen and allow the user to navigate between these smaller sets.

Solution

The following code creates a reusable Pagination component to use on any size data set. It sets up pagination for the dataset and allows a user to easily navigate between the smaller subsets of this data (subsets based on the interval size of the Pagination component).

Detailed explanation

First, we need to set up the Pagination component.  There are a few things to keep in mind.  One, how many items per page do we want to display.  Two, how many items are in our data set.  Three, do we want to enable "advanced movment", i.e. buttons to move to first or last page and buttons to move to next and previous pages.  The code below accounts for each giving navigation in both directions.  To create a simpler pagination component, you can easily remove the forward/back, first/last buttons.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" xmlns:renderers="com.rockfish.renderers.*" creationComplete="init()">
 <mx:Script>
  <![CDATA[
   import com.rockfish.events.PaginationEvent;
   
   private var _current:PaginationButton;
   private var items:Array;
   
   [Bindable]private var _count:int;
   public function set count(value:int):void
   {
    _count = value;    
   }
   
   [Bindable]private var _interval:int = 20;
   public function set interval(value:int):void
   {
    _interval = value;
   }
   
   [Bindable]private var _start:int;
   public function set start(value:int):void
   {
    _start = value;
   }
   [Bindable]private var _end:int;
   public function set end(value:int):void
   {
    _end = value;
   }
   
   private function init():void
   {
    setButtons(_count, _interval);
   }
   
   public function setButtons(ct:int, interval:int):void
   {    
    _count = ct;
    _interval = interval;    
    var i:int;
    var n:int = Math.ceil(ct/interval);    
    pageNav.removeAllChildren();
    items = new Array();
    for (i=0;i<n;i++)
    {
     var c:PaginationButton = new PaginationButton();
     c.label = Number(i+1).toString();
     c.page = Number(i+1);
     c.start = Number(i*_interval + 1);
     if (i == n-1)
      c.count = (ct % _interval == 0) ? _interval : ct % _interval; // if ct = _interval, still load last page
     else
      c.count = _interval;     
     if (i == 0)
     {      
      _current = c;
      _current.selected = true;
     }    
     c.addEventListener(PaginationEvent.PAGE_NAV, onChangePage);
     pageNav.addChild(c);
     items.push(c);
    }
    
    _start = 1;
    _end = _interval;
   }
   private function setRange():void
   {
    _start = _current.start;
    _end = _current.start + _current.count - 1;
   }
   private function onChangePage(event:PaginationEvent):void
   {    
    _current.selected = false;
    _current = event.currentTarget as PaginationButton;
    _current.selected = true;
    
    var curr:int = _current.page - 1;
    var tot:int = items.length;
    
    if (curr == 0)
     disableBack();
    else if (_current.page == tot)
     disableFwd();
    else
     enableAll();    
    
    var e:PaginationEvent = new PaginationEvent(event.type, _current);
    dispatchEvent(e);
    
    setRange();
     
   }
   private function gotoFirst(event:PaginationEvent):void
   {
    _current.selected = false;
    _current = items[0];
    _current.selected = true;
    disableBack();
    
    var e:PaginationEvent = new PaginationEvent(event.type, _current);
    dispatchEvent(e);
    
    setRange();
   } 
   private function goBack(event:PaginationEvent):void
   {
    var curr:int = _current.page - 1;
    var i:int = (curr >= 1)?curr - 1:0;
    _current.selected = false;
    _current = items[i];
    _current.selected = true;
    
    (i == 0)?disableBack():enableAll();
    
    var e:PaginationEvent = new PaginationEvent(event.type, _current);
    dispatchEvent(e);
    
    setRange();
    
   } 
   private function gotoLast(event:PaginationEvent):void
   {
    var i:int = items.length - 1;
    _current.selected = false;
    _current = items[i];
    _current.selected = true;
    disableFwd();
    
    var e:PaginationEvent = new PaginationEvent(event.type, _current);
    dispatchEvent(e);
    
    setRange();
   } 
   private function goForward(event:PaginationEvent):void
   {
    var curr:int = _current.page - 1;
    var tot:int = items.length - 1;
    var i:int = (curr < tot)?curr+1:tot;
    _current.selected = false;
    _current = items[i];
    _current.selected = true;
    
    (i == tot)?disableFwd():enableAll();
    
    var e:PaginationEvent = new PaginationEvent(event.type, _current);
    dispatchEvent(e);
    
    setRange();
   }
   private function disableBack():void
   {
    firstBTN.enabled = false;
    backBTN.enabled = false;
    fwdBTN.enabled = true;
    lastBTN.enabled = true;
   } 
   private function disableFwd():void
   {
    firstBTN.enabled = true;
    backBTN.enabled = true;
    fwdBTN.enabled = false;
    lastBTN.enabled = false;
   }
   private function enableAll():void
   {
    firstBTN.enabled = true;
    backBTN.enabled = true;
    fwdBTN.enabled = true;
    lastBTN.enabled = true;
   }
  ]]>
 </mx:Script>
 <mx:Metadata>
  [Event(name="pageNav",type="com.rockfish.events.PaginationEvent")]
 </mx:Metadata>
 <mx:HBox width="100%" backgroundAlpha="0" height="26" horizontalAlign="left">
  <mx:HBox backgroundAlpha="0">
   <mx:Canvas styleName="navBtn">
    <mx:Label text="{_start}-{_end} of {_count}" />
   </mx:Canvas>
   <renderers:PaginationButton id="firstBTN" label="&lt;&lt;" pageNav="gotoFirst(event)" enabled="false" />
   <renderers:PaginationButton id="backBTN" label="&lt;" pageNav="goBack(event)" enabled="false"/>    
  </mx:HBox>
  <mx:HBox id="pageNav" height="100%" backgroundAlpha="0">   
  </mx:HBox>
  <mx:HBox backgroundAlpha="0">    
   <renderers:PaginationButton id="lastBTN" label="&gt;" pageNav="goForward(event)" enabled="true"/>
   <renderers:PaginationButton id="fwdBTN" label="&gt;&gt;" pageNav="gotoLast(event)" enabled="true"/>        
  </mx:HBox>
 </mx:HBox>
</mx:Canvas>

From the previous code, we see a PaginationButton component.  The "look" of our component is written into the PaginationButton component.  So, the example exends the Canvas component for it's design.  The code to create the PaginationButton is as follows.  Things to remember include is the button enabled/selectable and is the button the currently selected button.  We also want to dispatch a special event for when the user selects "this" button.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="24" height="24" borderStyle="solid" borderColor="#FFFFFF" backgroundColor="#CCCCCC" backgroundAlpha="1" buttonMode="true" useHandCursor="true" enabled="true">
 <mx:Script>
  <![CDATA[
   import com.rockfish.events.PaginationEvent;
     
   [Bindable]private var backAlpha:Number = 0;
  
  
   [Bindable]private var _label:String;
   override public function set label(value:String):void
   {
    _label = value;
   }
   
   
   //[Bindable]private var _enabled:Boolean = true;
   override public function set enabled(value:Boolean):void
   {
    super.enabled = value;        
   }
   
   
   [Bindable]private var _selected:Boolean = false;
   public function set selected(value:Boolean):void
   {
    _selected = value;
    
    if (value)
     this.setStyle("backgroundColor","#a2a2a2");
    else
     this.setStyle("backgroundColor","#cccccc");    
   }
   
   private var _page:int;
   public function set page(value:int):void
   {
    _page = value;
   }
   public function get page():int
   {
    return _page;
   }
   
   private var _start:int;
   public function set start(value:int):void
   {
    _start = value;
   }
   public function get start():int
   {
    return _start;
   }
   private var _count:int;
   public function set count(value:int):void
   {
    _count = value;
   }
   public function get count():int
   {
    return _count;
   }
   
   private function onClick(event:MouseEvent):void
   {
    var e:PaginationEvent = new PaginationEvent(PaginationEvent.PAGE_NAV, this);
    dispatchEvent(e);
   }
  ]]>
 </mx:Script>
 <mx:Metadata>
  [Event(name="pageNav",type="com.rockfish.events.PaginationEvent")]
 </mx:Metadata>
 <mx:Label text="{_label}" verticalCenter="0" horizontalCenter="0" textAlign="center" color="#ffffff" selectable="false" buttonMode="true" useHandCursor="true"/>
 <mx:Canvas width="100%" height="100%" buttonMode="true" useHandCursor="true" backgroundAlpha="{backAlpha}" click="onClick(event)" />
</mx:Canvas>

The PaginationButton dispatches a special PaginationEvent when the user clicks on it.  When the event is dispatched, the Pagination component is listening for the "pageNav" event to know which portion of data to load.  The following code is the ActionScript for the PaginationEvent class.

package com.rockfish.events
{
 import com.rockfish.renderers.PaginationButton;
 
 import flash.events.Event;

 public class PaginationEvent extends Event
 {
  public static const PAGE_NAV:String = "pageNav";
  
  public var pageButton:PaginationButton;
  
  public function PaginationEvent(type:String, page:PaginationButton, bubbles:Boolean=false, cancelable:Boolean=false)
  {
   super(type, bubbles, cancelable);
   pageButton = page;
  }  
 }
}

And with that, our component is complete!  Next step is to build our application to use our new Pagination component.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:rockfish="com.rockfish.*" creationComplete="init()">
 <mx:Script>
  <![CDATA[
   import com.rockfish.renderers.PaginationButton;
   import com.rockfish.events.PaginationEvent;
   
   [Bindable]private var selectedItems:ArrayCollection;
   
   private function init():void
   {
    getItems(1,3);
   }
   
   private function onPageNav(event:PaginationEvent):void
   {
    var pb:PaginationButton = event.pageButton;
    
    getItems(pb.start, pb.count);
   }
   
   private function getItems(start:int, count:int):void
   {
    selectedItems = new ArrayCollection();
    
    var i:int;
    var n:int = count;
       
    for (i = 0; i < n; i++)
    {
     selectedItems.addItem(dataSet.getItemAt(start+i-1));
    }
   }
  ]]>
 </mx:Script>
 <mx:Binding source="dataSet.length" destination="paginator.count" />
 <mx:ArrayCollection id="dataSet">
  <mx:Object label="one" />
  <mx:Object label="two" />
  <mx:Object label="three" />
  <mx:Object label="four" />
  <mx:Object label="five" />
  <mx:Object label="six" />
  <mx:Object label="seven" />
  <mx:Object label="eight" />
  <mx:Object label="nine" />
  <mx:Object label="ten" />
  <mx:Object label="eleven" />
  <mx:Object label="twelve" />
  <mx:Object label="thirteen" />
  <mx:Object label="fourteen" />
  <mx:Object label="fifteen" />
  <mx:Object label="sixteen" />
  <mx:Object label="seventeen" />
  <mx:Object label="eighteen" />
  <mx:Object label="nineteen" />
  <mx:Object label="twenty" />
  <mx:Object label="twentyone"/>
 </mx:ArrayCollection>
 <rockfish:Pagination id="paginator" interval="3" pageNav="onPageNav(event)"  height="26"/>
 <mx:List id="pageItemsList" dataProvider="{selectedItems}" x="10" y="34" width="250">
  <mx:itemRenderer>
   <mx:Component>
    <mx:Label text="{data.label}" fontSize="24" height="44" />
   </mx:Component>
  </mx:itemRenderer>     
 </mx:List>
 
</mx:Application>

Our application implements our Pagination component and listens for the "pageNav" event.  When the event is dispatched, we filter down our list of items based on which PaginationButton was clicked.  We also have a reusable pagination control we can add to any future projects!

Pagination.zip
[Includes both the Pagination Library project as well as the Pagination test project.]
Report abuse

Related recipes