In order to make this work we need to have some data to make a results list from. In this example we are using two XML files to provide that data. Open up the pagDemoPN.fla and it's Document Class, PagDemoPN.as. You'll notice in the pageDemoPN.fla that I haven't lied to you, and there is nothing on the the stage and the only thing in the library is an instance of the Button component. Have a peek in the Component Assets -> ButtonSkins folder and you will find all of our custom skins. Under the Document Class setting we have declared PagDemoPN - no .as, just the class name - as the Document Class. Let's switch over to that file.

Starting from the top, we import the necessary classes.

package{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.text.*;
    import fl.controls.Button;
    import flash.external.ExternalInterface;
    import ca.xty.myUtils.NextPrevPN;
    import ca.xty.myUtils.CustomEvent;


The two custom classes we need are found in the ca.xty.myUtils folder and they are NextPrevPN.as and CustomEvent.as. We will discuss these, and the ExternalInterface class, in more detail as we go along. Next we set up our variables.

public class PagDemoPN extends MovieClip{
 
    //XML variables
    private var dataLoader:URLLoader = new URLLoader();
    private var xmlData:XML = new XML();
    private var musicInfoArray:Array;
 
    //On screen assets
    private var musicBut1:Button;
    private var musicBut2:Button;
    private var goBtn:Button;
    private var t1:TextField;
    private var ip1:TextField;
 
    //Data display variables
    private var barArray:Array;
    private var titleArray:Array;
    private var composerArray:Array;
    private var descArray:Array;
    private var songLengthArray:Array;
    private var cartArray:Array;
    private var titleHead:TextField;
    private var timeHead:TextField;
    private var composerHead:TextField;
    private var descHead:TextField;
    private var buyHead:TextField;
    private var buyArray:Array;
 
    //Pagination variables
    private var npT:NextPrevPN;
    private var npB:NextPrevPN;
    private var useNP:Boolean = false;
    private var maxNum:int = 7;
    private var numSongs:int;
    private var itemStart:int = 0;
    private var itemsToShow:int;
    private var pageStart:int = 1;
    private var numVisible:int;
    private var nBtn:Boolean;
    private var pBtn:Boolean;
    private var fBtn:Boolean;
    private var lBtn:Boolean;
    private var firstPage:Boolean = true;
    private var resultsTop:Sprite;
    private var resultsHolder:Sprite;
    private var newPage:int;
    private var newPageBut:int;
    private var numPages:int = 8;

    // TextFormats
    private var titleFormat:TextFormat;
    private var titleFormatC:TextFormat;
 
    //X and Y positions
    private var xPos:int;
    private var yPos:int;


First up, we get our XML variables ready. We declare a URLLoader to get the XML files off the server. Then we have a an XML object, and finally an array called musicInfoArray which is an array that we will be dumping all the results from the XML files in.

Our On Screen assets include the buttons to grab the music and another button which allows us to set the number of results we want to show at one time. The textfields are a label field and an input field to enter in the number of desired results.

The Data Display variables are the things we will be using to show the results. These consist of arrays and textfields.

The Pagination variables are the things will will be using to keep track of where we are and what is happening within the pagination process. The first two, npT and npB are variables to represent instances of our class NextPrevPN and stand for NextPrevPN Top and NextPrevPN Bottom. The useNP is a Boolean that will tell us whether or not we need to use an instance of the NextPrevPN class by determining the number of results and balancing that against the next variable maxNum. So, if we have 5 results and our maxNum is 10 then we do not need to use the NextPrevPN instance. If the opposite is true, then we need it. Then we have a bunch of integer values to pass information back and forth to the NextPrevPN class, a few more Booleans to let us know where we stand, and finally a couple of Sprites that we will be using as containers to hold our results. Using containers like this will provide us an easy way to remove the results in a single step. Notice that the two variables, maxNum and numPages have their values set. maxNum represents the maximum number of items to show per page, and numPages represents the maximum number of page number buttons to show at one time. You can alter these variables to meet your needs. The other two variables that are preset are itemStart and pageStart. The first time out itemStart will always be 0 and pageStart will always be 1. itemStart is 0 because this variable wants to get the first item in an array, which starts with a 0 index, and pageStart is set to 1 so that it makes sense to your visitors who think that the first page is 1, not 0.

Next up is our constructor.

public function PagDemoPN(){
 
    //Set up the TextFormats
    titleFormat = new TextFormat();
    titleFormat.color = 0x000000;
    titleFormat.font = "verdana";
    titleFormat.size = 10;
    titleFormat.align = "left";
 
    titleFormatC = new TextFormat();
    titleFormatC.color = 0x000000;
    titleFormatC.font = "verdana";
    titleFormatC.size = 10;
    titleFormatC.align = "center";
 
    //Give our XML Loader a Complete event listener
    dataLoader.addEventListener(Event.COMPLETE, loadData);
 
    //Put our assets on stage
    musicBut1 = new Button();
    musicBut1.x = 20;
    musicBut1.y = 10;
    musicBut1.width = 120;
    musicBut1.height = 20;
    musicBut1.label = "Rock Music (84)";
    musicBut1.addEventListener(MouseEvent.CLICK, musicButHandler);
    addChild(musicBut1);
 
    musicBut2 = new Button();
    musicBut2.x = 150;
    musicBut2.y = 10;
    musicBut2.width = 120;
    musicBut2.height = 20;
    musicBut2.label = "Easy Listening (4)";
    musicBut2.addEventListener(MouseEvent.CLICK, musicButHandler);
    addChild(musicBut2);
 
    t1 = new TextField();
    t1.x = 280;
    t1.y = 10;
    t1.width = 90;
    t1.height = 20;
    t1.text = "Items to Show:";
    t1.setTextFormat(titleFormat);
    addChild(t1);
 
    ip1 = new TextField();
    ip1.x = 375;
    ip1.y = 10;
    ip1.width = 30;
    ip1.height = 20;
    ip1.type = "input";
    ip1.border = true;
    ip1.defaultTextFormat = titleFormatC;
    ip1.text = String(maxNum);
    addChild(ip1);
 
    goBtn = new Button();
    goBtn.x = 410;
    goBtn.y = 10;
    goBtn.width = 30;
    goBtn.height = 20;
    goBtn.label = "Go";
    goBtn.addEventListener(MouseEvent.CLICK, goHandler);
    addChild(goBtn);
 
}

First we give our TextFormats some properties. They are nearly identical, with the only difference being the text align property.

Next we add a COMPLETE Event Listener to our XML dataLoader and direct it at a function called loadData.

Now we stick our stage assets in place. These are the buttons that will allow you to choose between Rock Music and Easy Listening. The numbers in parentheses represent the number of songs available in each category. I have taken a short cut here. In a real application, you would be counting the number of incoming results and appending that number to the button label. The last three assets go to make up our number-of-results-to-see-at-once feature. A title field with a label of Items to Show, an input field to gather the answer and the goBtn to make it happen. Our goBtn has an event listener for a CLICK event and takes you to a function called goHandler. Using the page number buttons this time out, you will also be affecting the total number of page buttons when you change the number of items to show. For instance, Rock Music has 84 items. The default is 7 items per page so we have a total of 12 page buttons. If you were to change the number of items to show to say 12, then you would have a maximum of 7 pages.

Now we'll look at the function that handles the user changing the number of items to show per page.

private function goHandler(e:MouseEvent):void{
    //As long as the input field is not empty, we change the variable maxNum to the contents of the ip1 textfield
    if(ip1.text != ""){
 maxNum = Number(ip1.text);
    }
    //If the boolean firstPage is not true we remove the data already displayed on stage and reset our variables to start over
    if(!firstPage){
 removeChild(resultsTop);
 removeChild(resultsHolder);
 if(useNP){
 removeChild(npB);
 useNP = false;
    }
    firstPage = true;
    itemStart = 0;
    }
    //Check to see if numSongs is greater than the new maxNum and then buildResults again using the the new maxNum
    if(numSongs > maxNum){
 useNP = true;
    }else if(numSongs <= maxNum){
 itemsToShow = numSongs;
    }
    // Now build the results
    buildResults();
}


The first thing we check is whether or not or input field, ip1, has anything in it. As long as it is not equal to nothing, we set the variable maxNum to whatever is in the ip1 field. Next we need to determine if the boolean firstPage is true or not. If it is not true, then that means we already have something on stage that we need to get rid of before proceeding. So we remove our two Sprites, resultsTop and resultsHolder. Now we check the useNP variable to see whether we are using an instance of our NextPrevPN on the bottom. If it's true, then we remove that instance as well. Once everything is off stage, we reset the firstPage variable to true, and our itemStart to 0. Finally we check to see if numSongs is greater than the new maxNum, and then buildResults() again using the the new maxNum.

Next we'll look at our music button handler.

private function musicButHandler(e:MouseEvent):void{
 switch(e.currentTarget.label){
   case "Rock Music (84)":
   dataLoader.load(new URLRequest("rockMusicPN.xml"));
   break;
 case "Easy Listening (4)":
   dataLoader.load(new URLRequest("easyMusicPN.xml"));
   break;
   }
}


We use a switch statement, with the label data as the criteria to tell us which button has been clicked, and then load the appropriate XML file. You'll remember that we already set up our listener for the dataLoader and declared it's function to be loadData.

private function loadData(e:Event):void {
 try{
   xmlData = new XML(e.target.data);
   parseData(xmlData);
 } catch (e:TypeError){
   trace("Unable to load XML");
   }
}


Here we assign the incoming data property to our XML object called xmlData, and then send that data to a function called parseData.

private function parseData(dataInput:XML):void {
 musicInfoArray = new Array();
 var infoList:XMLList = dataInput.song.composer;
 numSongs = infoList.length();
 for(var i:int = 0; i < numSongs; i++){
   var comp:String = dataInput.song[i].composer;
   var track:String = dataInput.song[i].title;
   var tl:String = dataInput.song[i].track_length;
   var d:String = dataInput.song[i].description;
   var musicObj:Object = {Composer:comp, Track:track, TrackLength:tl, Desc:d};
   musicInfoArray.push(musicObj);
 }
 //If the boolean firstPage is not true, then we remove the current data displayed and reset our variables to start over
 if(!firstPage){
   removeChild(resultsTop);
   removeChild(resultsHolder);
   if(useNP){
     removeChild(npB);
     useNP = false;
   }
   firstPage = true;
   itemStart = 0;
 }
 //If numSongs is greater then the maxNum to be shown, then we will need our next/prev feature so set the boolean useNP to true
 //and then buildResults
 if(numSongs > maxNum){
 useNP = true;
 }else if(numSongs <= maxNum){
 itemsToShow = numSongs;
 }
 // Now we build the results
 buildResults();
}


We set our musicInfoArray to empty by declaring a new instance of it. This array is going to hold an array of objects, with each object in the array containing all the information we need about one song. Next we declare a temporary variable called infoList that will hold our XMLList data, and we set it to point to the composer block in our XML file. We determine our numSongs variable by giving it the length value of our infoList. Notice here that the length property is declared as a function - length() - not the length property we normally see when getting the length of an array - someArray.length.
Now we use a for loop to gather all the available data and package it into an object - musicObj -, which we then push into our musicInfoArray. Once we have all the data stored away, we run through our check to see if this is the firstPage or not, and whether the numSongs is greater than the maxNum we set. This is the same routine as in our goHandler function we discussed above. Once we are ready, we buildResults().