Pages

Thursday, March 3, 2011

ArrayCollections, Binding, and Flex 3.5 and Repeaters

package inspired.flash.flex
{
   If there is interest, leave a comment and I will try to expand on this post.

Recently, I was working on some legacy code in Flex 3.5. We wanted to take this pile of inherited classes, and do some composition with them to make updates to the code easier. All was going well until I hit this very strange bug, where only the very last of the items in a repeater was getting properly updated.



Now, the true source of this bug was that we for some reason, had our data model maintaining references to the display object that was rendering the data. Meaning, instead of passing in a data reference to our display object and being happy, we had a double binding. This double binding was used by so many classes in different places, that it was not worth our time in trying to decouple it. (indeed, we spent 3 days trying to do so.)

However, the implementation of this bug, was that our repeater was creating extra instances of the display object, so that while the display had a reference to the correct data, the data did not have the correct reference to the display (except in the last case). We spent a few hours trying to decipher why this was, and eventually we discovered the problem.

We had an ArrayCollection that was bound as the source of the repeater, and we were changing the values of the ArrayCollection within a loop. Our code looked something like this:
boundedCollection = new ArrayCollection()
for(var i = 0; i < numberOfResponses; i++)
{
    if(needToAlterData(data[i]))
    {
       data[i] = alterData(data[i]);
    }
    boundedCollection.addItem(data[i]);
}

What this affectivly did, was each time the arrayCollection changed, it sent an event to the Repeater telling it to redraw itself thus destroying the instances that were bound to the data and just creating a bunch of dangling references.

The sollution to this problem was to change the code to the following:


boundedCollection = new ArrayCollection()
for(var i = 0; i < numberOfResponses; i++)
{
    if(needToAlterData(data[i]))
    {
       data[i] = alterData(data[i]);
    }
    boundedCollection.source.push(data[i]);
boundedCollection.refresh();

 This ensured that the repeater did not start drawing the displayObjects until after all the data was set, and fixed our bug.

I doubt many people are still using Flex 3.5, and in general you shouldn't need this functionality, but if you find strange behavior with your Repeater and your bound ArrayCollection, try this technique and odds are it will fix your problem.
}