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.

6 Responses to “Another Flex Weirdness/Gotcha”


  1. 1 shaun

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

    HTH

  2. 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. 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. 4 barneyb

    Thanks for the comments. I'm aware of how to make it work, I'm just surprised it doesn't work by default. I.e. there aren't per-property watchers, just per-object watchers. Refreshing the provider, reexecuting bindings, putting ChangeWatchers on the properties manually, etc., would al work, but it just seems weird to have to do that manually.

    I haven't tried it, but I'd be willing to bet that a custom itemRenderer that manually binds itself to the specific property (but is otherwise a "normal" renderer) would fix the issue. Then you could just use that in all your DataGrids and have it taken care of "automatically".

  5. 5 William Henry

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

  6. 6 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.

Leave a Reply