Binding issue with spark DataGrid’s selectedItem property

I was working with the spark DataGrid component for a Flex project and I wanted to bind a button’s enabled property to the DataGrid’s selectedItem (or selectedIndex) property so that the user can only click on the button if the selectedItem is not null. The code would look something like this:
<s:Button enabled="{myDataGrid.selectedItem}" />

I figured this would be as simple as it sounds, but I encountered some problems with it, particularly in 2 scenarios:

  1. When I delete the currently selected item by removing it from the dataprovider, the binding on selectedItem will not trigger and the button will remain in enabled=”true” state.
  2. When I assign a new dataProvider to the DataGrid while it has an item currently selected, the same thing happens: the getter method for selectedItem will not get updated for binding.

Interesting is that the selectedItem (selectedIndex, etc) properties are actually accurate at all times, but for some reason their getter methods are not always updated.
Note that the AdvancedDataGrid and the mx version of DataGrid doesn’t seem to have this issue, they work fine. The DataGrid I encounter this problem with is the spark one that comes with Flex SDK 4.5.1.
I made a quick fix to solve this problem.

You can see the original version on the left side with the issues, and the fixed one on the right. If you select an item on the left version and click on either the remove or the change button then the remove button will still be enabled and the selectedIndex will point to the previously selected item despite there’s no currently selected item. You can also trace the selectedItem and selectedIndex properties to see that their values are actually correct, they are just not getting updated for the use of binding.

[kml_flashembed movie=”” width=”490″ height=”357″ /]
It’s easy to apply a quick fix for these, the idea is to dispatch the FlexEvent.VALUE_COMMIT Event when needed. I extended the DataGrid class to come up with a reusable solution (until Adobe fixes this). Here’s how for the above scenarios respectively:

1. By overriding the set dataProvider setter method, you can add an EventListener on the dataProvider for its CollectionEvent.COLLECTION_CHANGE Event, and in that handler if a row was removed you just dispatch the VALUE_COMMIT FlexEvent which in turn will cause the required properties to be updated for binding.

2. In the same dataProvider setter method you can assign null to the selectedItem prior to calling super.dataProvider = value;
In this case, since you have the old dataProvider at the time of setting the selectedItem (so the selectedItem is not null yet) this will trigger the VALUE_COMMIT Event to be dispatched.
selectedItem = null;
super.dataProvider = value;

2.B Alternatively there’s another workaround. We can set selectedItem to null after the dataProvider is set. In this case though we need to manually dispatch the VALUE_COMMIT Event because the selectedItem is set to null after the dataProvider is set and at that point the Grid’s clearSelection method finds as the selection hasn’t changed (because selectedItem is already null after setting dataProvider to a new value) so it won’t dispatch the VALUE_COMMIT Event.
We still need to set selectedItem to null even though it’s already null because otherwise the selectedIndex and other corresponding properties wouldn’t get updated for binding (only the selectedItem property).
super.dataProvider = value;
selectedItem = null;
dispatchEvent( new FlexEvent(FlexEvent.VALUE_COMMIT) );

Here’s the BindableDataGrid class in place of the spark DataGrid that includes these fixes:

Update: Another scenario has been found thanks to MrBen:
If you remove the currently selected item by assigning a filterFunction to the dataProvider and calling refresh on it to update the view the usual issue happens: the selectedItem and selectedIndex properties have their correct values but their getter methods will not get updated. It’s easy to fix this though, we just need to dispatch the VALUE_COMMIT Event when refreshing is called on the dataProvider. The BindableDataGrid is updated to have this fix too.