Get Adobe Flash player

NextPrev Tutorial

This tutorial started out to be of average length, but as I got into it, I realized that there is quite a bit going on in the demo file that really should be explained. I am always muttering about the author leaving unexplained the one part I really wanted to know about, so, not wanting to do that, it's a bit longer than usual. And, if there are things I haven't explained to your personal satisfaction, my inBox is always open!

Where would you use pagination in Flash?

Anytime you need to display a lot of results, whether from a database, or, as in this tutorial's demo, from an XML file. In a full Flash site you generally have limited space in which to display data, but even if you are putting the results into a separate Flash movie, your space is still limited. Let's say you have a data set to display which includes images, a block of text, and a couple of buttons. Let's also say each result takes up 250 pixels of height. With the limit on a Flash movie's size being 2880 x 2880, vertically you'd only get 11 results to a single page.

The Demo Movie

The movie below feeds on 2 XML files containing the song data. I wanted the demo to make use of dynamically gathered data, and XML seemed to be the best choice under the circumstances. How you get your data is unimportant to the pagination concept, it's what we do with it afterwards that counts.

To see the flexibility of the class you can adjust the number of results to display.

Now, download the nextPrev.zip file and let's dig into the code and see how this works.

The files included in the nextPrev.zip are PagDemo.as and pagDemo.fla. This set of files shows the pagination working with both a top and bottom set of controls, while the PagDemoSingle.as and the pagDemoSingle.fla demonstrates the same class being used with only a single set of controls. The easyMusic.xml and rockMusic.xml files hold the data that we will be reading into the movie. And, you'll find the NextPrev.as class and the CustomEvent.as class files inside the ca.xty.myUtils folder system.

The XML files are very simple examples, and so I hope they don't need any detailed explanation, because I'm not providing any. There are quite a few good tutorials about using Flash and XML and, to do the subject justice, I'd need to make this tutorial even longer than it is. Besides, you will most likely have much more complex data to work with in a real situation, and consequently a much more complex XML file. What I'll mainly be dealing with is gathering the data from the XML file and packaging it up in a way that's easy for us to use.

The pagDemoSingle.as has sections commented out to show you what gets left out when you are using a single set of controls, and beyond that everything else is exactly the same.

There is also a text file called backToTop.txt. This is a tiny bit of JavaScript that we will use together with the ExternalInterface class provided by Flash.

As usual, the fla's are empty, except for a button in the library and the fact that the Document Class property is set to PageDemo or PageDemoSingle.

What's not included in the zip file this time out is an fla for CS3 - but don't despair! Creating one is dead easy. Make a new fla in CS3 with a width of 500 and a height of 600. Drage a Button component into the library and set your Document Class to read either pagDemo or pagDemoSingle - remember, no .as extension, just the class name. Make sure you have all the files included in the zip in the same folder as your CS3 fla and you're good to go.

So let's jump into the pagDemo.as file already!

PagDemo.as

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 pagDemo.fla and it's Document Class, PagDemo.as. You'll notice in the pageDemo.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. Under the Document Class setting we have declared PagDemo - 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.

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.NextPrev;
import ca.xty.myUtils.CustomEvent;

The two custom classes we need are found in the ca.xty.myUtils folder and they are NextPrev.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 PagDemo 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:NextPrev;
    private var npB:NextPrev;
    private var useNP:Boolean = false;
    private var maxNum:int = 5;
    private var numSongs:int;
    private var itemStart:int = 0;
    private var itemsToShow:int;
    private var showingItem:int = 1;
    private var numVisible:int;
    private var nBtn:Boolean;
    private var pBtn:Boolean;
    private var firstPage:Boolean = true;
    private var resultsTop:Sprite;
    private var resultsHolder:Sprite;

    // 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 ducks in a row. 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 texfields 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 NextPrev and stand for NextPrev Top and NextPrev Bottom. The useNP is a Boolean that will tell us whether or not we need to use an instance of the NextPrev 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 NextPrev 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 NextPrev 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.

Next up is our constructor.

public function PagDemo(){

    //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 (13)";
    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.

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;
        showingItem = 1;
        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 NextPrev on the bottom. If it's true, then we remove that instance as well. Once everything is off stage, we reset the first Page variable to true, the showingItem to 1 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 (13)":
            dataLoader.load(new URLRequest("rockMusic.xml"));
            break;
        case "Easy Listening (4)":
            dataLoader.load(new URLRequest("easyMusic.xml"));
            break;
    }
}

We use a switch statement, with the label data as the criteria, 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;
        showingItem = 1;
        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().

Page 2 | Page 3