Updating an ItemRenderer (style or state) based on the parent list based control’s number of items

I picked this one up from the Adbobe Forums, and for brevity I will post it Cookbook style.

Problem
You want to figure out how an itemRenderer can display itself or what state should be in, based on the number of items in the list it is assigned to.

Solution
Obviously you can pass in additional data (in this case the length of the parent list) to an ItemRenderer from the parent List based control when assigning the ClassFactory class factory responsible for producing renderer instances.

//WhateverRenderer.mxml
public var lengthInQuestion:int;

//List based parent, list parent...
var itemRenderer:ClassFactory = new ClassFactory(WhateverRenderer);
itemRenderer.properties = {lengthInQuestion: lengthInQuestion};

list.itemRenderer = itemRenderer;

Now all you need to do is track changes on the lengthInQuetion property and update the renderer accordingly. Easier said than done though. Flex passes in primitive types arguments by value so the renderer will need a reference to the outside object, etc… Yet you don’t really need to do all of that. There is a simpler solution. The renderer can query the parent list itself and update accordingly. Whenever there is a change in the dataProvider, the list based contros which is also the owner of the renderer will call the data setter upon the renderer passing in the new data. By overriding the data setter the developer can add code to “ask the owner” about its length, and then adjust the state or other required properties based on this value.

There are 2 ways to “ask the owner” in simple manner:

1. Direct inquiry by accessing the dataProvider.length. Since the owner is a DisplayObjectContainer some additional casting is required.

//WhateverRenderer.mxml
override public function set data(value:Object):void
{
	super.data = value;

	//cast to generic object in case this will be used accross multiple
	// controls List, DataGroup
	const numItems:int = Object(owner).dataProvider.length;

	//or cast to list
	const numItems:int = List(owner).dataProvider.length;

	//or cast to dataGroup
	const numItems:int = DataGroup(owner).dataProvider.length;

	....
	//update state, style or other visual properties
	....
}

2. Notification based inquiry by dispatching a custom event having a length property as payload.  You can have the event as bubbling and dispatch on the renderer itself or dispatch on the owner reference. The owner will listen for this custom event, and set the length on the event (event is processed synchronous). Execution will return to the renderer class and the length will be available inside the event as payload.

//QueryListEvent.as
public static const GET_LENGTH:String = "getLength";

public function QueryListEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
	super(type, bubbles, cancelable);
}

public var length:int;

override public function clone():Event
{
	var event:QueryListEvent = new QueryListEvent(type, bubbles, cancelable);
	event.length = length;
	return event;
}

//WhateverRenderer.mxml
override public function set data(value:Object):void
{
	super.data = value;

	var event:QueryListEvent = new QueryListEvent(QueryListEvent.GET_LENGTH);
	owner.dispatchEvent(event);

	//event payload is set in the list see code below
	const numItems:int = event.length;

	....
	//update state, style or other visual properties based on numItems
	....
}

//inside parent list based control, data group
//register listener for the query event
addEventListener(QueryListEvent.GET_LENGTH, dataProvider_getLengthHandler);

protected function dataProvider_getLengthHandler(event:QueryListEvent):void
{
	//set the length on the event to the dp length
	event.length = dataProvider.length;
}

Below there is a small app which illustrates how this works. For convenience I am only one one datasource (a random list of people names), and 3 daisy-chain different views of the same data.

– First list (on the left side) only displays the raw data.

– Second list component (middle) emphasizes the direct inquiry case, and it displays a filtered by name view of the persons collection. The renderer will ask the owner about the new length, and then adjust its background color and text color accordingly.

– Third list component (on the right side) is emphasizing the notification based inquiry case, and it displays a filtered by surname view of the persons collection. The renderer is dispatching the event ont the owner. It is also state based changing internal state upon new length passed back as event payload by the owner.


Get Adobe Flash player

DOWNLOAD PROJECT

P.S.
The second method was inspired by this original blog post which I read a while ago.

Leave a Reply

Your email address will not be published. Required fields are marked *

*