This class is pleasantly shorter than the last class we looked, eh? First of all, let me say that this class comes from an article I found at this site, which contains a terrific explanation of all the pieces involved, so I will only go over it briefly here.
package ca.xty.myUtils {
import flash.events.Event;
   
  public class CustomEvent extends Event {
    public static const CUSTOM:String = "custom";
    public var arg:*;
       
      public function CustomEvent(type:String, customArg:* = null, bubbles:Boolean = false, cancelable:Boolean = false) {
        super(type, bubbles, cancelable);
        this.arg = customArg;
      }
       
      public override function clone():Event {
        return new CustomEvent(type, arg, bubbles, cancelable);
      }
       
      public override function toString():String {
    return formatToString("CustomEvent", "type", "arg", "bubbles", "cancelable", "eventPhase");
      }
       
  }
}


All of the classes we have created in this tutorial and the others I have done are custom classes which extend Sprite or MovieClip. This is the first class which we have looked at which extends another class besides the default Sprite or MovieClip, in this case, the Event class. The reasoning behind this is that we want to use all the capabilities of the Event class as they are, but we want to add the ability, or extend it, to be able to pass back an argument within the event listener.

The variables we declare are both set to public as we will be needing them outside of this class. The first one is a static constant named CUSTOM which is typed to a string. The second one is called arg and is typed with an asterisk so that it can be any type of variable from a String to an Array and anything in between. This functionality enables you to reuse this class anytime you have a situation where you need to pass an argument back.

In the constructor we accept the parameters of type, which will be our CUSTOM variable, our customArg, which can be of any type and is optional because we have given it a default value of null, along with the bubbles and cancelable parameters which are also optional.

We have two public functions which override the clone function and toString functions found in the original Event class. To use this class you do something like this:

someObject.addEventListener(CustomEvent.CUSTOM, someFunction, false, 0, true);


And to dispatch the event you do this:

dispatchEvent(new CustomEvent(CustomEvent.CUSTOM, yourArgs));


We'll see this in action when we look at the NextPrev class next.

NextPrev Class

Well, it's be a bit of journey to get to this point, but here we are at last. Once again, first we import the necessary classes.
package ca.xty.myUtils {
  import flash.display.*;
  import flash.text.*;
  import flash.events.*;
  import flash.utils.*;
  import flash.net.*;
  import fl.controls.Button;
  import ca.xty.myUtils.*;


No surprises there. Next we set up our variables.
public class NextPrev extends MovieClip {
       
  private var nextBtn:Button;
  private var prevBtn:Button;
   
  private var _numItems:int;// This is our total number of items
  private var _maxItems:int;// This is the number of items we want to show at one time
  private var itemStart:int;// This is the number we use in our for loop to tell us which point in the array to start counting at
  private var _itemsToShow:int;// This is the number of items we are currently showing
  private var _txtColor:Number;// Text color
  private var _btnColor:Number;// Text color for the button
  private var showingItem:int = 1;// This is the visible equivalent of the var itemStart, but it needs to be 1 greater because humans start counting at 1, not like an array who starts at 0
  private var _nBtn:Boolean;// This variable lets us know whether the Next button is currently enabled
  private var _pBtn:Boolean;// This variable lets us know whether the Prev button is currently enabled
       
  private var statsArray:Array;// This is the array we will be passing back to the main class via our Custom Event
       
  //Display text fields
  private var st1:TextField;
  private var st2:TextField;
  private var st3:TextField;
  private var st4:TextField;
  //Our text formats
  private var showingFormat:TextFormat;
  private var showingFormatC:TextFormat;
  private var butFormat:TextFormat;
  //Our x and y position variables
  private var xPos:int;
  private var yPos:int;


The comments tell you pretty much what we are doing. Next up is our constructor function. From the main class we are receiving the Total Number of Items, the Number of Items to Show at Once, the visual Number of Items to be Shown, the Text Color, the Button text color.
public function NextPrev(numItems:int, maxItems:int, itemsToShow:int, txtColor:Number, btnColor:Number){


Now we assign our passed in parameters to our class variables.
_numItems = numItems;
_maxItems = maxItems;
_itemsToShow = itemsToShow;
_txtColor = txtColor;
_btnColor = btnColor;


Now we give our TextFormats some values and build the NextPrev buttons and TextFields.
showingFormat = new TextFormat();
showingFormat.color = _txtColor;
showingFormat.align = "left";
showingFormat.size = 10;
showingFormat.font = "verdana";
           
showingFormatC = new TextFormat();
showingFormatC.color = _txtColor;
showingFormatC.align = "center";
showingFormatC.size = 10;
showingFormatC.font = "verdana";
           
butFormat = new TextFormat();
butFormat.color = _btnColor;
butFormat.align = "left";
butFormat.size = 10;
butFormat.font = "verdana";
// Set our initial x and y positions
xPos = 0;
yPos = 0;
// Set up our previous button
prevBtn = new Button();
prevBtn.x = xPos;
prevBtn.y = yPos;
prevBtn.width = 60;
prevBtn.height = 20;
prevBtn.useHandCursor = true;
prevBtn.label = "<< Prev";
prevBtn.setStyle("textFormat", butFormat);
prevBtn.addEventListener(MouseEvent.CLICK, npHandler);
prevBtn.enabled = false;
addChild(prevBtn);
               
xPos += 70;
// Set up our text fields to show the results
st1 = new TextField();
st1.x = xPos;
st1.y = yPos;
st1.width = 60;
st1.text = "Showing";
st1.setTextFormat(showingFormatC);
addChild(st1);
           
xPos += 60;
           
st2 = new TextField();
st2.x = xPos;
st2.y = yPos;
st2.width = 50;
st2.text = String(showingItem) + " - " + String(_itemsToShow);
st2.setTextFormat(showingFormatC);
addChild(st2);
               
xPos += 45;
           
st3 = new TextField();
st3.x = xPos;
st3.y = yPos;
st3.width = 25;
st3.text = "of";
st3.setTextFormat(showingFormatC);
addChild(st3);
               
xPos += 20;
           
st4 = new TextField();
st4.x = xPos;
st4.y = yPos;
st4.width = 25;
st4.text = String(_numItems);
st4.setTextFormat(showingFormatC);
addChild(st4);
               
xPos += 35;
// Set up our Next button
nextBtn = new Button();
nextBtn.x = xPos;
nextBtn.y = yPos;
nextBtn.width = 60;
nextBtn.height = 20;
nextBtn.useHandCursor = true;
nextBtn.label = "Next >>";
nextBtn.setStyle("textFormat", butFormat);
nextBtn.addEventListener(MouseEvent.CLICK, npHandler);
//nextBtn.enabled = false;
addChild(nextBtn);
// Our variable itemStart will always be 0 at the beginning
itemStart = 0;
}


Where the buttons are concerned it's worth noting that they will use whatever the default skins are in your fla file. To change the appearance of your buttons, go into the library in the fla and play with the skins until you get them looking right for your application. This last parameter you pass in the NextPrev constructor is the button text color, so, if your buttons are black for instance, you can set the button text color to white.

After we put the previous button on stage, we add in the TextFields that will display our changing data. The first TextField, st1 simply contains the word "Showing". Next, st2 gives us the showingItem variable plus a hyphen plus the _itemsToShow variable. The TextField st3 just holds the word "of", while st4 displays the total number of items available held in the variable _numItems. Then we set up our next button, and lastly we set the variable itemStart to 0 for the first run through the data.

Now we'll look at the button handler function npHandler.
private function npHandler(e:MouseEvent):void{
  switch(e.target.label){
    case "Next >>":
      // Set our Prev button to be enabled
      prevBtn.enabled = true;
      // Add the _maxItems to our itemStart, _itemsToShow and showingItem variables
      itemStart += _maxItems;
      _itemsToShow += _maxItems;
      showingItem += _maxItems;
      // If our _itemsToShow variable is greater than or equal to our _numItems
      // we set our _itemsToShow to equal our _numItems and set our Next buttons enabled property to false
      if(_itemsToShow >= _numItems){
        _itemsToShow = _numItems;
        nextBtn.enabled = false;
      }
      // Now we update our text field
      st2.text = String(showingItem) + " - " + String(_itemsToShow);
      st2.setTextFormat(showingFormatC);
      // Here we package up our variables into our statsArray and send it back to our main class using our Custom Event
      statsArray = new Array();
      statsArray.push(showingItem);
      statsArray.push(itemStart);
      statsArray.push(_itemsToShow);
      statsArray.push(nextBtn.enabled);
      statsArray.push(prevBtn.enabled);
      dispatchEvent(new CustomEvent(CustomEvent.CUSTOM, statsArray));
      break;
    case "<< Prev":
      // First we set our Next buttons enabled property to true
      nextBtn.enabled = true;
      // Now we subtract our _maxItems from each of the other variables
      itemStart -= _maxItems;
      _itemsToShow -= _maxItems;
      showingItem -= _maxItems;
      // Now, if our _itemsToShow variable is greater than our _maxItems, then we might have an odd number as our _itemsToSho                

  // We use the modulo operater % to find the remainder of our _itemsToShow divided by our _maxItems
      // Example: if we have a total of 13 items and our _maxItems is 5, and we are at our last possible Next setting then we are currently
      // showing 11 to 13 of 13
      // So, _itemsToShow was 13, but we subtracted our _maxItems and ended up with 8 and we don't want that because pressing the prev button
      // should take us back to showing 6 - 10 of 13, not 6 - 8 of 13
      // By subtracting the variable mod (3 in this case) from our _itemsToShow we end up with 5, to which we then add our _maxItems to to end up with 10
      if(_itemsToShow > _maxItems){
        var mod = _itemsToShow % _maxItems;
        if(mod > 0){
          _itemsToShow -= mod;
          _itemsToShow += _maxItems;
        }
      }
      // Now, if our _itemsToShow is less than or equal to _maxItems and our _numItems is greater than our equal to our _maxItems
      // then we want to make sure that our itemsToShow equals _maxItems and that our previous button has its enabled property set to false
      if(_itemsToShow <= _maxItems && _numItems >= _maxItems){
        _itemsToShow = _maxItems;
        prevBtn.enabled = false;
      }
      st2.text = String(showingItem) + " - " + String(_itemsToShow);
      st2.setTextFormat(showingFormatC);
      statsArray = new Array();
      statsArray.push(showingItem);
      statsArray.push(itemStart);
      statsArray.push(_itemsToShow);
      statsArray.push(nextBtn.enabled);
      statsArray.push(prevBtn.enabled);
      dispatchEvent(new CustomEvent(CustomEvent.CUSTOM, statsArray));
      break;
    }
}


The npHandler function is pretty well commented, and, hopefully, makes sense to you. In a nutshell, what we are doing is adding (for next) or subtracting (for previous) our _maxItems variable from the other variables. We need to check if any of the variables go over or under the limits and adjust things accordingly if they do. By toggling the enabled property of our next and prev buttons we avoid a case where the numbers could go negative, by simply not allowing that situation to take place. In both the next and the prev cases we set up our statsArray to a new, empty array, then add in the updated variables using push() and then dispatch our CustomEvent back to the Document Class to allow it to show the next, or previous, set of results.

The next function takes care of our manual updates for the instance of the NextPrev class that was not clicked, in the case where you are using both a top and bottom instance.
public function manualUpdate(showItem:int, sItem:int, itemsTS:int, nBtn:Boolean, pBtn:Boolean):void{
  showingItem = showItem;
  itemStart = sItem;
  _itemsToShow = itemsTS;
  nextBtn.enabled = nBtn;
  prevBtn.enabled = pBtn;
  st2.text = String(showingItem) + " - " + String(_itemsToShow);
  st2.setTextFormat(showingFormatC);
}


First, we receive in the parameters we sent from the Document Class and transfer them to our local class variables. The next and prev buttons enabled properties are updated accordingly, and we update the information displayed in our TextFields so that now the two instances of the NextPrev class we are using are identical. And that's all there is to it, believe it or not.

A Real World Example

With limited space and somewhat restricted capabilities, it's hard to give you a real world example of this here. I am currently working on the prototype for an upcoming project which will demonstrate the actual usage of pagination with a bit more depth. You can find the example here. The only category that has any test data in it is the Genre category, and you will need to scroll down it's results list until you come to Popular Styles. Click on that and you will get a sub menu, from which you choose Rock. All the buttons to play the music or add to cart are working. Keep in mind it is a work in progress, so no guarantee that everything works as it's supposed to, but it should give you an idea of what things can be accomplished with pagination in Flash versus PHP/HTML.

Where to Next?

Suppose you want to have individual page buttons instead of being stuck with consecutively moving through the list of results using the next and previous buttons? This might be a good idea if your results set gives you 50 pages. All the raw material you need is here. You will need a few more variables, such as numPages, but it should be relatively easy to work out. Give it a try, and if you beat me to it, put up a new tutorial here
on ActionScript.org yourself that extends our NextPrev class. Go on, you can do it!

A Word of Thanks

To all the people who have written to me with questions and suggestions, thank you! It's great to hear from you, and really nice to know that these tutorials have been helpful. Some of you have written with terrific suggestions to tighten up the code, or take care of situations I hadn't imagined, and that feedback is very helpful in my continuing quest to learn and write better code. A frequently asked question I receive is, Are you
available to be hired? The answer is yes, so if you have a project in mind, feel free to contact me and I'll see if I can help out. And, last, but not least, a big thumbs up to the folks at ActionScript.org who make all this community interaction possible through their hard work. The Flash community is a stronger and better place because of you!