Flex and the ‘tab’ key

Ran into another pickle not too long ago involving the tab key. By default, the tab key cycles through text inputs and buttons et cetera based on the tab order you define. But what if you want the tab key to do something different? If anyone out there has tried to prevent the default behavior of the tab button with Flex before, they will know that it is not as easy as you’d think.

With every other keyDown or keyUp event, you can usually capture the event and call a preventDefault() in order to prevent the default behavior. However, for some odd reason, the keyDown event behaves differently when the tab key is pressed. Why only the tab key? I don’t know. I suppose that is a question for Adobe.

Either way, I managed to hack my way around the limitations and capture the tab keyDown anyway. Now, try to stay with me here, because what I ended up having to do still doesn’t quite make complete sense to me.

With my specific example, I was using a custom item renderer inside a DataGrid. Normally the tab key would highlight the next object to the DataGrid in the canvas, but I really wanted it to go to the next (or what I considered “next”) element inside the DataGrid. However, I imagine that this solution could be used in other places as well.

As close as I can tell, as soon as the tab key goes up the inner workings of flex change the focus to the next object in the tab order. This seems to happen before any sort of keyDown handler is called, so the following does NOT work:

<mx:TextInput keyDown="myKeyDownHandler(event)" xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
    public function myKeyDownHandler(event:KeyboardEvent):void {
        if (event.keyCode == 9) {
            // tab key
            event.preventDefault();
            ....

The only reason I can figure as to why this doesn’t work is because by the time myKeyDownHandler() gets called, the default event actions have already been executed… i.e. the damage has been done.Trying the same thing on the keyUp handler yields the same results. Stepping through Flex source leads me to believe that it is not a KeyboardEvent that actually makes the ‘tab’ happen, but a FocusEvent, but the keyFocusChange event doesn’t even get fired on the current object when the tab key is hit (Adobe bug?) so that is out of the question also. So how can I trap an event that seems to be phantom?

I finally managed to figure out how to get it to work, and it was really weird what ended up working. I found out (through a lot of debugging and various different wild-guesses) that I can capture the FocusEvent on the tab keyDown through doing a combination of things:
1) First, I had to trap the keyDown that is fired when the tab key is pressed.
2) In that same event, I had to call a (some object).setFocus() to trigger a FocusEvent (this.setFocus() was called in this example)
3) Finally, in the onKeyFocusChange event of the object that the setFocus() was called on in step two, call an event.preventDefault()

It seems as though by calling a setFocus() while in a keyDown event handler, I triggered an “early” FocusEvent that I can then catch myself. The FocusEvent that gets captured by the onKeyFocusChange event in step three for some reason IS that tab event. Through Flex voodoo and wizardry I managed to prematurely cause the tab FocusEvent myself, and then prevent it. Weird, right?

I really have no idea why, but it works. If somebody can explain it to me, be my guest. I imagine it has something to do with the way Flex’s event queue works. In the meantime, enjoy the solution. View source is turned on for your pleasure.

  1. No comments yet.

  1. No trackbacks yet.