ActionScript 3.0, Adobe Flex

Flex : Pageable ArrayCollection with support for active paging

Yesterday one of the developers in my company had the need for a PagedArrayCollection. A quick search on Google revealed only this implementation, which turned out to be buggy so I decided to implement one myself.

I designed an interface called IPagedCollection which in combination with an extension of the existing mx.collections.ArrayCollection implementation would do the job.

Only hurdle was the need to override addItemAt and removeItemAt as the autoUpdate doesn’t seem to work when a filterFunction is employed. I will look in to this phenomena, but as for now a call to refresh after inserting or removing does the job nicely.

The code itself is quite simple, I have also created a small demo-application which illustrates the use of the collection.

Live Demo

Download of Sources

/**
 * Copyright(c) 2008 HelloGroup A/S, some rights reserved.
 * Your reuse is governed by the Creative Commons Attribution 3.0 Denmark License
**/
package com.hello.collections
{
	public interface IPagedArrayCollection
	{
		function get currentPage() : Number
		function set currentPage( value:Number ) : void;

		function get numberOfPages() : Number;

		function get pageSize() : Number;
		function set pageSize( value:Number ) : void;

		function get lengthTotal() : Number;
	}
}
/**
 * Copyright(c) 2008 HelloGroup A/S, some rights reserved.
 * Your reuse is governed by the Creative Commons Attribution 3.0 Denmark License
 *
 * Known Issues:
 * - When the collection changes in size or pagesize, the currentPage is not updated. This is a problem if currentPage is set to a higher value than in the new collection.
**/
package com.hello.collections
{
	import mx.collections.ArrayCollection;
	import mx.events.CollectionEvent;

	public class PagedArrayCollection extends ArrayCollection implements IPagedArrayCollection
	{
		private var _currentPage:Number = 1;
		private var _numberOfPages:Number = 1;
		private var _pageSize:Number = 10;

		public function PagedArrayCollection(source:Array=null)
		{
			super( source );
			filterFunction = filterData;
			addEventListener( CollectionEvent.COLLECTION_CHANGE, onChange );
		}

		/**
		 * Adds an item to the collection at the specified index.
		 *
		 * @param item Item to be added
		 * @param index Index of the item to be added
		 *
		 * Note: Needs to be overridden in order to trigger refresh. AddItem eventually calls this function so its not needed to override addItem
		 */
		override public function addItemAt( item:Object, index:int ) : void
		{
			super.addItemAt( item, index );
			refresh();
		}

		/**
		 * Removes the item from the collection at the specified index
		 *
		 * @param index Index of the item to be removed
		 * @return The item removed
		 *
		 * Note: Needs to be overridden in order to trigger refresh
		 */
		override public function removeItemAt( index:int ) : Object
		{
			var removedItem:Object = super.removeItemAt( index );
			refresh();
			return removedItem;
		}

		protected function onChange( event:CollectionEvent ) : void
		{
			if( _numberOfPages != numberOfPages )
			{
				_numberOfPages = numberOfPages;
				onPagingChange( PagedCollectionEventKind.NUMBEROFPAGES_CHANGE );
			}
		}

		protected function onPagingChange( kind:String ) : void
		{
			dispatchEvent( new CollectionEvent( CollectionEvent.COLLECTION_CHANGE, false, false, kind ) );
		}

		[ChangeEvent("collectionChange")]
		public function get currentPage() : Number
		{
			return _currentPage;
		}
		public function set currentPage( value:Number ) : void
		{
			_currentPage = value;
			refresh();
			onPagingChange( PagedCollectionEventKind.CURRENTPAGE_CHANGE );
		}

		[ChangeEvent("collectionChange")]
		public function get numberOfPages() : Number
		{
			var result:Number = source.length / pageSize;
			result = Math.ceil( result );
			return result;
		}

		[ChangeEvent("collectionChange")]
		public function get pageSize() : Number
		{
			return _pageSize;
		}
		public function set pageSize( value:Number ) : void
		{
			_pageSize = value;
			refresh();
			onPagingChange( PagedCollectionEventKind.PAGESIZE_CHANGE );
		}

		[ChangeEvent("collectionChange")]
		public function get lengthTotal() : Number
		{
			return source.length;
		}

		private function filterData( item:Object ) : Boolean
		{
			var dataWindowCeiling:Number = pageSize * currentPage;
			var dataWindowFloor:Number = dataWindowCeiling - pageSize;

			var itemIndex:Number = getItemIndex( item );

			var result:Boolean = dataWindowFloor <= itemIndex && itemIndex < dataWindowCeiling;
			return result;
		}
	}
}

/**
* Copyright(c) 2008 HelloGroup A/S, some rights reserved.
* Your reuse is governed by the Creative Commons Attribution 3.0 Denmark License
**/
package com.hello.collections
{
public class PagedCollectionEventKind
{
public static const CURRENTPAGE_CHANGE:String = "currentPageChange";
public static const PAGESIZE_CHANGE:String = "pageSizeChange";
public static const NUMBEROFPAGES_CHANGE:String = "numberOfPagesChange";
}
}

Advertisements

12 thoughts on “Flex : Pageable ArrayCollection with support for active paging

  1. This is a great class, thanks for sharing – I’m noticing that it’s having a hard time when you filter by headers or by a .sort call.Do you have any insight into why this might be?Thanks again for sharing your work.

  2. I was wondering…. when using this collection, and using it as a data source for say something like a datagrid, does it load all of the data up front, or on demand?

  3. Thanks for your comment.The collection doesn’t actually handle loading of the data, in regards to getting data its just as simple and “stupid” as a normal arraycollection. I think however its an interesting point so I will look into it and create a posting about it in the near future.

  4. it appears that the switch from Blogspot to WordPress have taken these lines of code as casualties…
    I apologize, but seeing that the source code is available for download I’m not going to do anything about it… 🙂

    1. Hi Theo,

      The problem is that its right now using the filter to actually create the paging function… the first step should be to have a data-adapter attached to it so it can work seamlessly with the serverside… the challenge is not to get the overhead associated with tying to a distinct server model, such as webservices, remoteobject or XML. Once the data-adapter is implemented instead of using the filter element, it will be possible.

      The initial implementation was just a quick solution to a concrete problem, creating a data-adapter however would be cool, so I will look into it.

      // Peter

    1. The SysOp had changed the default documents list not to include Index.html… I have updated the link.
      Hope you find it useful, please comment on it if you have any thoughts, I would love to hear what you think.

      // Peter

  5. Any news about the filtering of the paged array collection? Any ideas how to implement both paging and “common” filtering?

    1. Hello Ani,

      Thanks for reading (and keeping me to my promise).
      I suppose I owe it to you guys to post an update supporting filtering… so let me take a look at it again and see what I can do.

      Thanks for commenting,
      Peter

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s