Another Flex Weirdness/Gotcha

Another little gotcha to watch out for with Flex.  If you have an ArrayCollection of Objects that are backing a DataGrid, you can add/remove objects from the ArrayCollection and the DataGrid will update.  However, updating properties on the objects doesn't seem to update the DataGrid until you force a redraw via some other means (e.g. resorting the rows).  In my particular case, the Objects in question were non-dynamic instances of a custom class that are [Bindable] at the class level.

This was unexpected to me, but on further reflection seemed quite explicable (though not necessarily reasonable).  It seems that individual DataGrid cells ought to be bound to the property they're fronting, rather than only the rows being bound to the Objects.  But with the way the internals of DataGrid work, the property selection is dynamic (using [] notation), which is unbindable directly.  You can avoid it with a bindable function, of course, but it seems DataGrid (at least in Flex 2.0.1) doesn't do that.

I'll probably dig into this some more (since I really don't want to have a zillion executeBindings() calls all over the app).  If anyone has any insight into this behaviour, I'd be quite interested to hear it.

13 responses to “Another Flex Weirdness/Gotcha”

  1. shaun

    I think I call grid.dataProvider.refresh from a custom event handler when i've completed updating the dataprovider.

    HTH

  2. Brandon Ellis

    Hi,
    Instead of sorting the rows, you should be able to call ArrayCollection.refresh(); and that will trigger an update.

    I'm doing that in an app of mine. :)

  3. JesterXL

    You have a lot more options.

    1.

    [Bindable]
    PersonVO
    {
    public var firstName:String;
    public var lastName:String;
    public var address:AddressVO;
    }

    Using an ArrayCollection that's full of PersonVO's, your DataGrid would have each column bound to 1 of the properties. In this case, it's assumed that your AddressVO has a toString() method to return a nicely formatted Address string.

    2. Use a label function. When a variable changes on your VO, your label function will run and you can format it how you wish.

    3. Use an itemRenderer. While it's implied you are building the itemRenderer per column, you basically get your data function which is fed the object from the ArrayCollection, so you don't necessarely have to use the column name in question.

    In all scenarios above, if you change the "firstName" property, the field will update in the DataGrid (whether on its own, via your labelFunction getting called again, or your itemRenderer's data setter getting run). If it's not, you are either not using the Bindable tag up top, or not strongly typing your variables.

  4. William Henry

    You can use myDataGrid.executeBindings(false);
    The argument determines whether there is recursion.

  5. Garnet

    I agree about weirdness. It's easy to do cool stuff in Flex quickly, but then you run into a quirk that takes way too long to solve.

    I have this as the data provider for my AdvancedDataGrid:
    private var dpList:ArrayCollection = new ArrayCollection([
    {Ref:true, Name:"Garnet",
    ReadTime:400}]);

    In timer routines I want to
    dpList[0].ReadTime++

    But the grid won't update. I tried all of these, and none of them work to cause an update:
    dpList.refresh();
    adgList.validateNow();
    adgList.executeBindings(false);

    The one thing that does work is doing
    dpList.addItem(…)

    Guess I need to trace into the source for addItem and figure out what it is doing.

  6. Terry

    I had a similar problem. In the snippet below dataObjects is an ArrayCollection that was set as my dataProvider on my AdvancedDataGrid. I could not get updates to refresh until I added the last line.

    public function changeData(event:MouseEvent):void {
    var data:Array = dataObjects.getItemAt(2) as Array;
    data[1] = "pmWizard";

    data = dataObjects.getItemAt(1) as Array;
    data[1] = "treeKing";
    data[4] = 1967;

    ArrayCollection(dataGrid.dataProvider).refresh();
    }

  7. Vitaly Sazanovich

    I also had a similar problem. My DataGrid would update its content only when the popup was opened for the first time. I debugged this into a stale reference to the old instance of the DataGrid. I'm using PureMVC and in the constructor of the mediator for the Popup I was registering mediators for canvases within that popup:
    facade.registerMediator(new AdPlacesCanvasMediator(settingsTitleWindow.adPlacesCanvas));
    Now, the fix was to unregister them in the onClose event:
    facade.removeMediator(AdPlacesCanvasMediator.NAME);
    Otherwise a new set of mediators would be created with the next popup. Is it a bug of PureMVC? RegisterMediator should take mediator's name as a parameter and do not create a new instance of the mediator if it is already registered.

  8. Dylan

    I was having a similar problem using a repeater with a custom component that has a nested second repeater. Repeater A was registering updates to the Bindable object just fine but Repeater B was not updating itself even though the ArrayCollection B it was using as a dataSource had changed.

    I tried invalidating the components housing the repeaters but that did not work. I finally took a stab at useing the arrayCollection.refresh() and it worked like magic. Note: everything is [Bindable], it just another one of those quirks.

  9. Jon

    Gotta say thanks for this….was driving me crazy.

    ArrayCollection(dataGrid.dataProvider).refresh(); worked perfectly for me.

  10. BS_C3

    Hi!

    That's a really interesting post (it actually helped me solve a problem that was driving me crazy!!).

    I had the same issue with a linkbar. The dataprovider was an array collection that looked like

    <Object label =
    .
    .
    .

    The labels where not updated when the variables value changed… I had to force a dataprovider.refresh() to get it work. It took me some time and some posts to figure it out.

    The most interesting thing is that this "weirdness" still exists in flex 3.2 …

    And just FYI, a quite useful link about dataproviders limitations:
    http://www.adobe.com/devnet/flex/quickstart/using_data_providers/#limitations

    Regards,
    BS_C3

  11. David Lincoln

    I have a similar weirdness. The ArrayCollection. refresh() works as expected. But it has a side effect. If the number of rows in my datagrid exceeds the capability of the window it is in, (vertical scroll bars are needed), then when I click in a row after the first couple, the screen refreshes automatically and scrolls up past the row I clicked on. I have tried capturing the verticalSrollPosition of the datagrid prior to the refresh, then resetting it afterward, but that does not help. It's like a catch-22. Either the cell does not refresh properly and the scroll works fine, or vice-versa.

  12. wellings.eu » Updating a datagrid dataprovider with custom item renderer not working as expected?

    [...] http://www.barneyb.com/barneyblog/2007/06/23/another-flex-weirdnessgotcha/ About Visit 's Website. View other posts by [...]