flex multiple array collections with a single datasource - apache-flex

How can I populate multiple datagrids in flex with a single datasource that is filtered differently for each datagrid. I'm assigning the event.result from my remote object call to three different array collections, each with its own filter function. When I assign and refresh the filter functions, they each affect all array collections. So, the results of the last array collection refresh end up in all three datagrids.

You probably need to use ObjectUtil.copy on your event result to have 3 separate ArrayCollections, one for each DataGrid... otherwise they all point at the same memory location of the single ArrayCollection and any changes made to it will be reflected in all DataGrids.
var AC1:ArrayCollection = event.result as ArrayCollection;
var AC2:ArrayCollection = ObjectUtil.copy(AC1) as ArrayCollection;
var AC3:ArrayCollection = ObjectUtil.copy(AC1) as ArrayCollection;

I would make copies of your data provider, ie:
var myDataArray:Array; // this contains your original data.
dataGrid1.dataProvider = new ArrayCollection(myDataArray.concat());
dataGrid2.dataProvider = new ArrayCollection(myDataArray.concat());
dataGrid3.dataProvider = new ArrayCollection(myDataArray.concat());

The solutions that have been provided may not behave as you might wish they would. An ArrayCollection technically consists of a model and a "view" into the model. In my understanding, both the solutions that have been provided create a copy of the model. This means if you add an item to one ArrayCollection it won't show up in another regardless of whether it would match that ArrayCollection's filter. Usually you want it to be a part of the model of the other ArrayCollections as well but only be visible if the added item passes the respective ArrayCollection's filter. You can share the "model" amongst ArrayCollections while having separate views into the model like so:
var collection1:ArrayCollection = new ArrayCollection();
var collection2:ArrayCollection = new ArrayCollection();
collection2.list = collection1.list;
var collection3:ArrayCollection = new ArrayCollection();
collection3.list = collection1.list;
Now you can add an item to any of the three collections and it will show up in the others. However, you can have separate filters and sorts on each individual ArrayCollection and that won't affect what's viewable in the others. You can read more about this here:
http://aaronhardy.com/flex/collections-and-chaining-for-separate-presentation/

Related

Flex List limit number of elements

Is it possible to define a property to limit the number of elements which will appear in a mx:List ? I've read about setting the property rowCount, but I don't see any effect.
Can a filter be applied to accomplish this? My intention was to avoid removing the items from the list/array collection, but simply "hide" them. Can this be done?
You can "hide" items from display in a List-based class, without modifying your underlying source data, by using a Collection class, such as an ArrayCollection, and filtering the data.
Read these docs on Collection filtering.
To quote:
You use a filter function to limit the data view in the collection to
a subset of the source data object. The function must take a single
Object parameter, which corresponds to a collection item, and must
return a Boolean value specifying whether to include the item in the
view. As with sorting, when you specify or change the filter function,
you must call the refresh() method on the collection to show the
filtered results. To limit a collection view of an array of strings to
contain only strings starting with M, for example, use the following
filter function:
public function stateFilterFunc(item:Object):Boolean
{
return item >= "M" && item < "N";
}
A different option is to use a new arraycollection and get your limited items from your big arraycollection :
//get first 10 elements
myArrayCollection = new ArrayCollection( myBigArrayCollection.toArray().slice(0,9) );
if you want to work with pagers, you could hold a counter where you keep track of what page the user is on, and get the next elements from you big array collection. example:
//this is just a (very) simple example
//page = integer (counter) for knowing which page the user is on
page = 0;
page_low = page*10;
page_high = page_low + 9;
myArrayCollection = new ArrayCollection( myBigArrayCollection.toArray().slice(page_low,page_high) );
(still using a filter is a more elegant solution)

Adobe Flex arraycollection

I want to use single collection object to two different UI components. 1. Datagrid and 2nd is chart component. I dont want to change anything inside the arraycollection object but I want to use it at the same time with two different component with minor changes. I know we can use filter function some how but not sure how to apply filter to arraycollection object so that one component (datagrid) can use the original arraycollection object and second component (chart) used the modified one.
Thanks,
If you use the same ArrayCollection as the dataProvider for two different components, then any filter or sort applied to that ArrayCollection will show up in both components.
What you want to do cannot be done.
However, you can create multiple ArrayCollections based on the same source and apply filters to them differently. Conceptually something like this:
public var arrayCollection1 : ArrayCollection = new ArrayCollection();
public var arrayCollection2 : ArrayCollection = new ArrayCollection();
protected function onIGotTheArray(value:Array):void{
arrayCollection1.source = value;
arrayCollection2.source = value;
dataGrid.dataProvider = arrayCollection1;
chart.dataProvider = arrayCollection2;
}
Now you can apply a filter to the first arrayCollection without affecting the second arrayCollection, or vice versa.
This is the preferred approach in my experience.

Alternative to data binding

As an alternative to binding an array collection to a data grid's data provider, could I assign the array collection as the data provider to the data grid on it's creation and everytime the array collection is updated execute invalidateProperties(); invalidateList(); to re-render the data grid?
Does my described approach make sense?
Does my described approach make sense?
Sort of. If you have an arrayCollection ( ac) defined using a get/set method, there is no reason you can't set the dataPRovider on your DataGrid in the set method, every time the data is changed.
If you do that, then you most likely will not have to update the properties or displayList of the DatGrid, because the mere fact of replacing the dataProvider will do it for you.
Something like this:
private var _ac : ArrayCollection;
public function get ac():ArrayCollection){
return this._ac;
}
public function set ac(value:ArrayCollection){
this._ac = value;
this.dataGrid.dataProvider = this.ac;
}
Bingo, every time that the ac value is updated, so will the dataProvider on the DataGrid.

Flex 3 Using an ArrayCollection to Populate Both a Datagrid and a ComboBox

I use this arrayCollection to populate a Flex 3 Datagrid. I'd also like to use this arrayCollection to populate a comboBox with the Name node.
In the arrayCollection, I've got the Name listed twice. I've got two rows in the Datagrid.
If I set the ComboBox's labelfield to Name, then the Name will be listed twice in the ComboBox menu. Is there a way to use this arrayCollection and have each Name listed only once in the comboBox?
I can always make another loop and array collection for the Name, but I was wondering if there were a better way.
var i:uint;
for (i=0; i<myArray.length; i++){
myDGArray = [
{Name: myArray[i].Name, Subject: 'Math:', Pass: myArray[i].math_pass, Fail: myArray[i].math_fail},
{Name: myArray[i].Name, Subject: 'Reading:', Pass: myArray[i].reading_pass, Fail: myArray[i].reading_fail}
]
}
myAC=new ArrayCollection(myDGArray);
Thank you.
-Laxmidi
I'm a bit confused. Based on your code sample, the name will be listed twice in the ComboBox because the same name is used twice in your dataProvider.
You may want o consider converting your dataProvider to two separate ListCollectionView objects, provide different filtering on each object and use those each as se[separate dataProviders.
In psuedo code this is how I'd do it:
public var comboBoxCollection : ListCollectionView = new ListCollectionView(myAC );
public var dataGridCollection : ListCollectionView = new ListCollectionView(myAC );
The apply filtering on the comboBoxCollection to filter out entries with duplicate names. More info on collection filtering in the docs.

FLEX: what's the best way to check if an Object has been already added to an ArrayCollection?

I need to merge 2 arrayCollection and avoid duplicates. They contain objects with their own attributes. I would like to avoid duplicates.
thanks
var array1:ArrayCollection = new ArrayCollection();
var array2:ArrayCollection = new ArrayCollection();
var array3:ArrayCollection = new ArrayCollection(array1.source);
for(var i:int;i<array2.length;i++){
if (!(array3.contains(array2.getItemAt(i))))
array3.addItem(array2);
}
That's the simplest algorithm, and works for not so large lists. The contains method will check for object references and you should use your custom method in case you are defining duplicates by looking on objects properties.
If the 2 ArrayCollections potentially contain exactly the same objects, it would be
if (acDestination.getItemIndex(acSource[i]) == -1)
// add to the destination
If the objects aren't exactly the same but you'd like to avoid duplicate values on a key field, try a filter function on the destination ArrayCollection.

Resources