tags:

views:

403

answers:

2

I have a DataGrid and I set the DataProvider to my data. When my data changes the DataGrid loses the selected row and the scroll bar jumps back to the top. How do I maintain the selection and scroll position?

+4  A: 

If you just want to maintain position:

in whatever function is changing the data, first capture the selected index

var myidx:int = new int(myDG.selectedIndex);

and the scroll position

var myVertPos:int = new int(myDG.verticalScrollPosition);

run the code that changes the data then do the above steps backwards:

myDG.selectedIndex = myidx;
myDG.verticalScrollPosition = myVertPos;

Oh and you will probably want to do a check to make sure that the selected index is not over the length of items now in your DG and select the last one if it is. In my experience setting the vertical scroll position greater than the max just results in scrolling to the max.

invertedSpear
How does this work if the new dataProvider puts the selectedItem in a different index, which it probably will?
Robusto
it doesn't.. that's why I was trying to ask the OP's intent (maintain item, or maintain index) I think you might be able to get it to maintain the item by using something like `var myItem:Object = myDG.selectedItem;` and `myDG.selectedItem = myItem;` but I'm not sure how I would work that out without a lot of testing. Then you would need to find the scroll position somehow... It's much more complicated to maintain the item :-)
invertedSpear
This seems to work well enough as the number of items in my list isn't changing, just the associated data. Thanks.
FigBug
Isn't the whole point exactly that data (eg fetched from a database) could be changed. Best thing, I found, is keeping a selectedId variable synced with the selection, then hang a change watcher on the datasource and go reset the selection by iterating through all the rows. TODO: how to guarantee the change wachter will run only *after* the data has refreshed in the grid, so there probably is a better way
FredV
invertedSpear: that will not work because AS3 has the big disadvantage of not overloading and using the equals method on user defined classes (like in Java or any other decent language). The selectedItem = myItem will not work since flex compares references of objects (which have changed after reloading)
FredV
Thanks FredV, I was afraid of that, which is why I didn't post it as an answer :) I know maintaining the index is the simple way to do, and it sounds like the OP got what s/he wanted out of that, but I was curious about how to maintain an item. I like the simplicity of keeping that global var for it.
invertedSpear
+1  A: 

There is a way. you need to extend the DataGrid Class and add a String property uniqueIdField.

Set the vaule of uniqueIdField to a property of the objects in the dataset that is unique.

then override the set dataProvider method as below: this will work if the columns are not sorted. FIXED*I now have the issue that when the column is sorted the correct row hightlights but the scrollbar does not mve to the value (as one of its properties that affect the sort has changed).*

The code below set the the scrollbar to the correct position.

override public function set dataProvider(value:Object):void { var vScroll:int = 0; //check to see if we reselect previous selected item //and save current postion if(uniqueIdField.length > 0 && selectedItem != null) { uniqueIdData = this.selectedItem[uniqueIdField]; vScroll = this.verticalScrollPosition; }

super.dataProvider = value;

        if(uniqueIdField.length > 0 
        && uniqueIdData != null
        && selectedItems.length <= 1)

{
var currentObj:Object; var found:Boolean = false;

if(dataProvider is ArrayCollection)
{

 //find object in dataprovider
 for(var i:int=0; i < dataProvider.length; i++)
 {
  currentObj = dataProvider.getItemAt(i);
  if(currentObj[uniqueIdField] == uniqueIdData)
  {
   this.selectedItem = currentObj;
   found = true;
   vScroll = this.selectedIndex;
   break;

  }
 }

 if(!found)
 {
  this.selectedItem = null;
  uniqueIdData = null;
 }


}

//notify that the item has been selected, found or null this.verticalScrollPosition = vScroll; dispatchEvent(new ListEvent(ListEvent.CHANGE));

}

David