Posted by: edsyrett | 15 August 2008

Focus issues in Flex


You’ll be familiar with FocusManager and how it manages focus around text input controls, right? Well, once again, the browsers have hit back…

It seems, at least in Internet Explorer 7, that if you hit tab on a text box, it will allow Flex to process the keydown, but then it will merrily move focus off the Flash Player altogether. In other words IE captures the tab key to move around its own controls.  If your Flex app has forms made up of text boxes, that’s something you really don’t want.

The only way I’ve found to get around this is a JavaScript hack in the wrapper HTML.  It basically sets up a listener for keyboard events and passes the tab key down to the Flash Player.

In addition, if your Flex app starts up showing a text box (e.g. a login form) then that won’t get focus.  The reason for this is that Flash Player itself doesn’t automatically get focus.  If you click anywhere on the Flex App, you’ll find that the first textbox gets focus as you might expect.

This little hack fixes both these issues in Internet Explorer.   I tried these fixes in Firefox as well, but although it fixes the issue with tabbing around forms, I just could not make Firefox give Flash Player the focus on startup.

In the wrapper HTML, I’ve added some extra JavaScript – setupKeyListener() is executed on load, and it sets up the listener, and then tries to set focus to the Flash Player. Note that I’ve named the object mainApp – this has to match the id field passed to the AC_FL_RunContent() function, or the id of the <object> tag.

<script language="Javascript" type="text/javascript"> function setupKeyListener() { // Add the event handler detectEvent on the keydown event document.onkeydown = detectEvent; if (isIE) { // force the focus var flashPlayer = document.mainApp || window.mainApp; flashPlayer.focus(); } else { // For Firefox, it's just not worth bothering...it won't work. } } // this is the detectEvent event handler function detectEvent(e) { var evt = e || window.event; // check for the TAB key if (evt.keyCode == 9) { // call the actionscript function to pass it the SHIFT key pressed mainApp.handleExternalTabKey(evt.shiftKey); // prevent the browser the default actions for the key pressing return false; } else { return true; } } </script> <body scroll="no" onload="setupKeyListener()"> ...etc

In your main application class, you’ll need to export the handleExternalTabKey() function something like this:

private function onCreationComplete(event:FlexEvent):void { ...stuff... ExternalInterface.addCallback("handleExternalTabKey", handleExternalTabKey); } private function handleExternalTabKey(name:String):void { if (name == "false") { // only the TAB key has been pressed focusManager.getNextFocusManagerComponent().setFocus(); } else { // the combination of SHIFT+TAB has been pressed focusManager.getNextFocusManagerComponent(true).setFocus(); } }

Update

In response to Daniel’s comment below, I had another look at the issue with setting focus to the Flex app at startup in Firefox. I’m happy to say that I found a solution that seems to work at least on our app. Here’s the new version of setupKeyListener()…

function setupKeyListener() { // Add the event handler detectEvent on the keydown event document.onkeydown = detectEvent; setTimeout('mainApp.focus()', 100); }

It seems that in IE you can go right ahead and set focus to the Flash instance and it works fine. But it occurred to me that in Firefox the Flash instance might not have loaded fully at the point I called focus(). So just for a lark I put the focus() call on the end of a timer, and it seems to work. I’ve just got an arbitrary value of 100ms in the code above. I guess it could be anything because all I’ve really done is allow control to return from the setupKeyListener() function so that Firefox can finish whatever it’s doing and then call the focus() at some later time. Incidentally, the code above now seems to work for IE and Firefox.

Hopefully this is some use (particularly to Daniel) and I’m certainly going to add this fix to a bunch of our apps.

Thanks to Daniel for prompting me to have another look at this…

Advertisements

Responses

  1. you write “I tried these fixes in Firefox as well, but although it fixes the issue with tabbing around forms, I just could not make Firefox give Flash Player the focus on startup”

    were you able to find a sln to this?

  2. Hi Daniel,

    In response to your comment I had another look at the Firefox thing. It must have been the fact that I was taking a totally fresh look at this problem as I tried something different and it seemed to work. I’ve updated the post with my solution.

    Thanks for commenting.

  3. I have a minor question regarding this very good solution.
    Since we are adding a javascript into the HTML wrapper, is it not possible that the browser does not executes the javascript depending upon the browser settings.

  4. Hi Dan,

    Yes I think most, if not all, browsers can be set to ignore any javascript. However, if someone did actually do this, I suspect that most of the websites on the planet would not run properly because they would need at least some javascript to provide the functionality. So I don’t believe it would reasonable for a user of your website to switch off javascript and expect either yours or anybody else’s web apps to run. For that reason, we just take it for granted that the javascript will run.

    I hope that answers your question…..

    Cheers,

    Ed.

  5. Thank you for a very helpful post. In my testing I came up with a variation that may be a bit easier to maintain, as it embeds the JavaScript code in the Flex app so there is no need to modify index.template.html.

    I added the following to my application tag:
    creationComplete=”ExternalInterface.call(‘function(){window.document.’+this.id+’.focus();}’)”

    By having Flex call the JavaScript once the application finishes loading, there is no need for a timer delay. It worked for me in both IE and Firefox.

    • That’s fantastic….

      This solution is so much more elegant than faffing about with the HTML wrapper for getting focus onto Flash Player on startup. Thanks to Jay for posting this.

      However, we still have to fix the problem of tabbing going back out to the browser, so if there is a solution to that which doesn’t involve hacking the HTML wrapper then I’m sure we’d love to hear about it.

      • Try this…

        In the oncreation init function…

        ExternalInterface.call(“function(){window.document.” + this.id + “.focus();setTimeout(‘window.document.” + this.id + “.setDefaultFocus()’, 1000);}”);

        then have something like this in your app:

        public function setDefaultFocus():void{
        this.txtEmailAddress.setFocus();
        }

  6. Working on a flash-based Telnet client here. Firefox contained the tab key presses in the flash player, but IE did not… this did the trick for me.

    For Telnet into Unix boxes, auto completion with the Tab key is a must have… so this was one of the last steps to take my product into production

    Thanks!

  7. […] Focus issues in Flex August 2008 8 comments 3 […]

  8. tried with all the possible ways step by step mentioned but , I cannot achieve the retaining of focus . IS there ANY ONE who can figure it out , what the problem is ??


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: