We have a SelectionRestorer class that does just this. Just add it to the MXML and set it's target to the list/combobox/whatever you want to repopulate, and it does all the watching for you.
HTH,
Sam
We're hiring! Developers and QA in Washington, DC area (or looking to relocate) should send resumes to [email protected].
package com.atellis.common.controls {
import flash.events.Event;
import flash.events.EventDispatcher;
import mx.events.CollectionEvent;
import mx.events.ListEvent;
public class SelectionRestorer extends EventDispatcher
{
private var previousSelectedItems:Array;
private var _compareField:String;
[Bindable("compareFieldChanged")]
public function get compareField():String {
return _compareField;
}
public function set compareField(value:String):void {
_compareField = value;
dispatchEvent(new Event("compareFieldChanged"));
}
private var _compareFunction:Function;
[Bindable("compareFunctionChanged")]
public function get compareFunction():Function {
return _compareFunction;
}
public function set compareFunction(value:Function):void {
_compareFunction = value;
dispatchEvent(new Event("compareFunctionChanged"));
}
private var _target:Object;
[Bindable("targetChanged")]
public function get target():Object {
return _target;
}
public function set target(value:Object):void {
if (_target) {
if (_target.dataProvider) {
_target.dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, dataChangeHandler);
}
_target.removeEventListener(ListEvent.CHANGE, selectionChangeHandler);
_target.removeEventListener(CollectionEvent.COLLECTION_CHANGE, dataChangeHandler);
}
_target = value;
if (value) {
value.addEventListener(ListEvent.CHANGE, selectionChangeHandler, false, 0, true);
value.addEventListener(CollectionEvent.COLLECTION_CHANGE, dataChangeHandler, false, 100.0, true);
if (value.dataProvider) {
value.dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE, dataChangeHandler, false, 100.0, true);
}
}
dispatchEvent(new Event("targetChanged"));
}
public function refresh():void {
if (useMultipleSelect) {
previousSelectedItems = target.selectedItems;
} else {
previousSelectedItems = [target.selectedItem];
}
}
public function clear():void {
previousSelectedItems = null;
}
private function compareFieldFunction(o1:Object, o2:Object):Boolean {
if (o1 == null || o2 == null) {
return false;
}
var v1:Object = o1[compareField];
var v2:Object = o2[compareField];
return v1 != null && v2 != null && v1 == v2;
}
private function compareEqualityFunction(o1:Object, o2:Object):Boolean {
if (o1 == null || o2 == null) {
return false;
}
return o1 == o2;
}
private function get useMultipleSelect():Boolean {
return "selectedItems" in target && "allowMultipleSelection" in target && target.allowMultipleSelection;
}
private function selectionChangeHandler(event:ListEvent):void {
refresh();
}
private function dataChangeHandler(event:CollectionEvent):void {
if (previousSelectedItems == null || previousSelectedItems.length == 0) {
return;
}
if (target.dataProvider == null) {
previousSelectedItems = null;
return;
}
var comparer:Function = compareFunction;
if (comparer == null) {
if (compareField == null) {
comparer = compareEqualityFunction;
} else {
comparer = compareFieldFunction;
}
}
// when you assign an array to ListBase.selectedItems, it removes all items from the array,
// so we need to build two arrays, one to assign, and one for current state
var indices:Array = new Array();
var items:Array = new Array();
var dpIndex:int = 0;
for each(var newItem:Object in target.dataProvider) {
for(var i:int = 0; i<previousSelectedItems.length; i++) {
if (comparer(newItem, previousSelectedItems[i])) {
indices.push(dpIndex);
items.push(newItem);
previousSelectedItems.splice(i, 1);
break;
}
}
if (previousSelectedItems.length == 0) {
break;
}
dpIndex++;
}
target.validateNow();
if (useMultipleSelect) {
target.selectedIndices = indices;
} else {
target.selectedIndex = indices[0];
}
if (items.length) {
previousSelectedItems = items;
} else {
previousSelectedItems = null;
}
}
}
}