Unwanted binding - apache-flex

The situation is simple. I have a datagrid that gets its data from a webservice.
When data from the webservice is retrived it calls the following function:
private function onListReg():void
{
arrRegOld = WSAutoreg.list.lastResult as ArrayCollection;
arrReg = WSAutoreg.list.lastResult as ArrayCollection;
dgReg.dataProvider = autoreglist;
}
dgReg is the Datagrid. the arr variables are ArrayCollections defined like so:
private var arrRegOld:ArrayCollection = new ArrayCollection;
[Bindable]
private var arrReg:ArrayCollection = new ArrayCollection;
The intent is when I hit a update button, it compares arrRegOld with arrReg and see if any values have changes. The problem is whenever I change values on the Datagrid it changes on both the dataProvider and on both ArrayCollections.
Does anyone know why is this happening? What should I do so that the binding applies only to one ArrayCollection?
Appreciate any tip.
- Mike

Your lists are sharing the same objects, if you modify the first element from arrReg you will see the modification also in arrRegOld - it is not related to binding. You need to clone the objects. You have several choices:
a) Implement a clone method for your objects (recommended)
b) Use a generic method like this one:
private function clone(source:Object):*
{
var array:ByteArray=new ByteArray();
array.writeObject(source);
array.position=0;
return(array.readObject());
}
and call arrRegOld = clone (arrReg); after arrReg = WSAutoreg.list.lastResult as ArrayCollection;

Related

HierarchicalCollectionView: One time sort?

I have an AdvancedDataGrid that relies on a HierarchicalCollectionView as it's dataProvider. What I'd like to do is sort the data when it is first loaded, but then disable the sort so that anything that is added after the initial load doesn't cause the grid to auto-sort again. I tried something like this:
this._myDataProvider = new HierarchicalCollectionView(
new HierarchicalData(this._model.rootTasks));
var mySort:Sort = new Sort();
mySort.fields = [new SortField("startDate")];
this._tasksDataProvider.sort = taskSorting;
this._tasksDataProvider.refresh();
this._tasksDataProvider.sort = null;
But setting the sort to null just leaves the data unsorted. I guess what I'm asking is: how can I sort the underlying hierarchical data since it seems setting the sort property will keep it dynamically sorting. Thanks for any help you can provide.
Personally, I would change the sort order when you're getting the data. Either it's done on the server side or when you parse the data (ie. in your model). You can do a one time sort using Array with sortOn.
you can
1. sort the original data with sort function,
2. clone content and put it to a new collection with no sort (be careful do and make a manual clone),
3. just use the new data collection.
I had the same kind of problem until I realized that the sorting with Sort object does not change the "physical" ordering of the items within the Collection, so when you remove the Sort, the next refresh reverts the view to the actual "physical" ordering.
Similarily as stated above, I solved by it by cloning the sub-collections into sorted order this way:
public static function buildPositionSort():Sort
{
var dataSortField:SortField = new SortField();
dataSortField.name = "position";
dataSortField.numeric = true;
dataSortField.descending = false;
var sort:Sort = new Sort();
sort.fields = [ dataSortField ];
return sort;
}
/**
* This method is used to create a clone of ArrayCollection, because sorting does not
* actually change the physical ordering of the items.
*/
public static function createSortedArrayCollectionCopy(source:ArrayCollection):ArrayCollection
{
var target:ArrayCollection = new ArrayCollection();
source.sort = buildPositionSort();
source.refresh();
for each (var item:Object in source)
{
if (item.children != null) item.children = createSortedArrayCollectionCopy(item.children);
target.addItem(item);
}
return target;
}

datagrid cannot be found

I create each datagrid to be added to the NavigatorConent(), however, how do I retrieve the datagrid by ID so that I can point the ArrayCollection to datagrid's dataprovider?
private var pdg:String;
private function stabAdd():void {
var dg1:DataGrid = new DataGrid();
var cn:NavigatorContent = new NavigatorContent();
stab.addElement(cn);
cn.name = "nc"+nu;
dg1.id = "nc"+nu;
pdg = dg1.id;
dg1.addEventListener(MouseEvent.CLICK,cc);
nu++;
This will throw an error which pdg cannot be found, I wonder why:
trace(DataGrid(pdg));
The purpose of nu++ is to assign a
unique name (dg1, dg2, etc) to each
datagrid so that I can assign AC to
that datagrid's dataprovider
I can respect the need to give every component a unique name. The appropriate way to do that in ActionScript is not to specify the id/name field of the component, but rather to create an instance of the component as a variable. Something like this:
protected var myGrid : DataGrid;
And you can now access myGrid anywhere in the component, or in it's children, without creating some complicated scheme. If you need multiple DataGrid's you can store them in an array:
protected var myGridArray : Array = new Array();
And somewhere later in your code--probably createChildren() do something like this:
loop
var newGrid : DataGrid = new DataGrid()
myGridArray.push(newGrid);
end loop
For the most part, this is how all the Flex list based components do it with itemRenderers. They have an array of visible renderers.
As stated in #J_A_X_ comments, you are trying to convert pdg--a string--into a DataGrid. I would expect that to return a null value, as Flex casts tend to fail quietly.
If you want more help, you'll have to tell us the explicit error that you're receiving, possibly with line numbers and more code.

Object to arraycollection then to datagrid

Say, linedataColl is an AC that contains 200+ of rows extract from CSV and in my design, I wish to additem into SuperDataCollection object by object but the only problem was I'm unable to see any data display in "S" which is a datagrid. What wrong with my code?
var superDataCollection:ArrayCollection = new ArrayCollection();
var dc:ArrayCollection = new ArrayCollection();
var di:Object = new Object();
for(var aa:int=0; aa<5;aa++){
di.username = linedataColl[aa].username;
di.email = linedataColl[aa].email;
dc.addItem(di);
superDataCollection.addItem(dc);
s.dataProvider = dc;
}
Don't set the dataProvider within the for loop. You only need to set it once, and the datagrid will detect changes to the ArrayCollection you specify as a dataProvider.
The best thing to do is set it after you completely build up the ArrayCollection 'dc'.
Perhaps your problem will be fixed by this...
}
s.dataProvider = dc;

Problem converting Array to Arraylist for dataProvider

private var MealsListResult:ArrayList = new ArrayList;
protected var _data:resultData = new resultData;
private function resultHandler():void
{
var Meals:Array = _data.Meals;
MealsListResult = _data.Meals as ArrayList;
MealDataGrid.dataProvider = Meals;
MealListView.dataProvider = MealsListResult;
}
Should this be working? the MealDataGrid is populating based on the array, but I am debugging and MealsListResult is null. but _data.Meals is not and I dunno if I'm missing something simple.
I can get it to work by doing it like: var MealsListResult2:ArrayList = new ArrayList(Meals); but I feel as though the first method should be working as well!
(there's mxml list and datagrid and such not shown here of course)
if _data.Meals is its runtime type is an array then _data.Meals as ArrayCollection will failed. but, new ArrayCollection(_data.Meals as Array) will working fine.
CMIIW
i guess your problem is you can't use single object as 2 or more different ui dataprovider.
try to use
MealDataGrid.dataProvider = _data.Meals;
MealListView.dataProvider = ObjectUtils.clone(_data.Meals);
UPDATE:
sorry i miss readed, i though it was ArrayColletion. but all you need to do is the same like ArrayCollection

Assign Xml Values to dynamically created components

xml values are stored in 'arr' array collection. depending on the length of the array stored, the below described components are created and assign those values to relevant components dynamically.
For Example:
AdvanceSearch.mxml is one component, and another components as advanceSearchAtom.mxml. within 'advanceSearchAtom' has some sub components as textbox, combo box etc,. we can add many advanceSearchAtom.mxml inside 'AdvanceSearch.mxml'.
var container : AdvanceSearch;
var adv : advanceSearchAtom;
for(var i:int=0;i<arr.length;i++) {
adv = new advanceSearchAtom();
adv.field.text = arr[i].field;
adv.value.selectedIndex = arr[i].value;
container.addChild(adv);
}
Please let me know if anybody come across this type of problem. if any relevant link is appreciable. Thanks in advance
You didn't mention it, but I guess the problem is that you're getting null reference error (1009) on the following lines:
adv.field.text = arr[i].field;
adv.value.selectedIndex = arr[i].value;
Am I right?
This is because field and value are not yet created. As per the default component instantiation, Flex creates the children only when it is required - i.e., when it is to be displayed.
You can either listen to the creationComplete event of the AdvanceSearchAtom component and update the values from there; or have Binadble public variables in the AdvanceSearchAtom class, bind them to field.text and value.selectedIndex and assign xml values to those variables in the loop.
Using creation complete:
public var container:AdvanceSearch;
public var searchItems:Array = [];
public var arr:Array;
//assuming that arr has been initialized with xml values.
var adv:AdvanceSearchAtom;
for(var i:int=0;i<arr.length;i++) {
adv = new AdvanceSearchAtom();
adv.addEventListener(FlexEvent.CREATION_COMPLETE, onAtomCreated);
container.addChild(adv);
searchItems.push(adv);
}
public function onAtomCreated(e:Event):void
{
var adv:AdvanceSearchAtom = e.currentTarget as AdvanceSearchAtom;
if(!adv)
return;
var index:Number = searchItems.indexOf(adv);
adv.field.text = arr[index].field;
adv.value.selectedIndex = arr[index].value;
}
Using data binding:
Inside AdvanceSearchAtom.mxml
<mx:TextInput id="field" text="{textValue}"/>
<mx:ComboBox id="value" selectedIndex="{comboIndex}"/>
In the script block of AdvanceSearchAtom.mxml
[Bindable]
public var textValue:String;
[Bindable]
public var comboIndex:Number;
var adv:AdvanceSearchAtom;
In the AdvanceSearch class:
for(var i:int=0;i<arr.length;i++) {
adv = new AdvanceSearchAtom();
container.addChild(adv);
adv.field.text = arr[i].field;
adv.value.selectedIndex = arr[i].value;
}

Resources