Setting focus in Flex using the Focus Manager

The following example shows how you can set focus on a TextInput control in Flex by using the Flex FocusManager class and the setFocus() method.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/09/23/setting-focus-in-flex-using-the-focus-manager/ -->
<mx:Application name="FocusManager_setFocus_test"
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Script>
        <![CDATA[
            import mx.controls.Alert;

            private function submitButton_click(evt:MouseEvent):void {
                Alert.show(evt.currentTarget.label,
                            Object(focusManager.getFocus()).name);
            }

            private function resetButton_click(evt:MouseEvent):void {
                username.text = "";
                password.text = "";
                Alert.show(evt.currentTarget.label,
                            Object(focusManager.getFocus()).name);
            }
        ]]>
    </mx:Script>

    <mx:ApplicationControlBar dock="true">
        <mx:Button label="Set focus to Username"
                click="focusManager.setFocus(username);" />
        <mx:Button label="Set focus to Password"
                click="focusManager.setFocus(password);" />
    </mx:ApplicationControlBar>

    <mx:Form id="form"
            defaultButton="{submitButton}">
        <mx:FormItem label="Username:">
            <mx:TextInput id="username" />
        </mx:FormItem>
        <mx:FormItem label="Password:">
            <mx:TextInput id="password"
                    displayAsPassword="true" />
        </mx:FormItem>
        <mx:FormItem direction="horizontal"
                horizontalAlign="right"
                width="100%">
            <mx:Button id="submitButton"
                    label="Submit"
                    click="submitButton_click(event);" />
            <mx:Button id="resetButton"
                    label="Reset"
                    click="resetButton_click(event);" />
        </mx:FormItem>
    </mx:Form>

</mx:Application>

View source is enabled in the following example.

Due to popular demand, here is the “same” example in a more ActionScript friendly format:

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/09/23/setting-focus-in-flex-using-the-focus-manager/ -->
<mx:Application name="FocusManager_setFocus_test"
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white"
        initialize="init();">

    <mx:Script>
        <![CDATA[
            import mx.containers.ApplicationControlBar;
            import mx.containers.Form;
            import mx.containers.FormItem;
            import mx.containers.FormItemDirection;
            import mx.controls.Alert;
            import mx.controls.Button;
            import mx.controls.TextInput;

            private var usernameButton:Button;
            private var passwordButton:Button;
            private var username:TextInput;
            private var password:TextInput;
            private var submitButton:Button;
            private var resetButton:Button;

            private function init():void {
                usernameButton = new Button();
                usernameButton.label = "Set focus to Username";
                usernameButton.addEventListener(MouseEvent.CLICK,
                            usernameButton_click);

                passwordButton = new Button();
                passwordButton.label = "Set focus to Password";
                passwordButton.addEventListener(MouseEvent.CLICK,
                            passwordButton_click);

                var appControlBar:ApplicationControlBar;
                appControlBar = new ApplicationControlBar();
                appControlBar.dock = true;
                appControlBar.addChild(usernameButton);
                appControlBar.addChild(passwordButton);
                addChildAt(appControlBar, 0);

                username = new TextInput();
                username.name = "username";

                password = new TextInput();
                password.displayAsPassword = true;
                password.name = "password";

                submitButton = new Button();
                submitButton.label = "Submit";
                submitButton.name = "submitButton";
                submitButton.addEventListener(MouseEvent.CLICK,
                            submitButton_click);

                resetButton = new Button();
                resetButton.label = "Reset";
                resetButton.name = "resetButton";
                resetButton.addEventListener(MouseEvent.CLICK,
                            resetButton_click);

                var formItem1:FormItem = new FormItem();
                formItem1.label = "Username:";
                formItem1.addChild(username);

                var formItem2:FormItem = new FormItem();
                formItem2.label = "Password:";
                formItem2.addChild(password);

                var formItem3:FormItem = new FormItem();
                formItem3.direction = FormItemDirection.HORIZONTAL;
                formItem3.setStyle("horizontalAlign", "right");
                formItem3.percentWidth = 100;
                formItem3.addChild(submitButton);
                formItem3.addChild(resetButton);

                var form:Form = new Form();
                form.defaultButton = submitButton;
                form.addChild(formItem1);
                form.addChild(formItem2);
                form.addChild(formItem3);
                addChild(form);
            }

            private function usernameButton_click(evt:MouseEvent):void {
                focusManager.setFocus(username);
            }

            private function passwordButton_click(evt:MouseEvent):void {
                focusManager.setFocus(password);
            }

            private function submitButton_click(evt:MouseEvent):void {
                Alert.show(evt.currentTarget.label,
                            Object(focusManager.getFocus()).name);
            }

            private function resetButton_click(evt:MouseEvent):void {
                username.text = "";
                password.text = "";
                Alert.show(evt.currentTarget.label,
                            Object(focusManager.getFocus()).name);
            }
        ]]>
    </mx:Script>

</mx:Application>

36 thoughts on “Setting focus in Flex using the Focus Manager

  1. Another nice, clean example but… there are loads of issues with the FocusManager. In fact, it rarely works as you would expect and definitely not as your simple example implies. It’s very difficult to set the focus when a .swf loads and the ‘I-Beam’ caret and where you actually are on the page constantly gets out of sync, confusing users.

    All in all, it is very broken except in the simplest circumstances so before you try and implement it tyry Googling for “Flex setfocus problem” and see what you will be up against.

  2. This is a great example but what would you do to make a TextInput field have focus by default?

  3. time2design,

    I think something like this should work:

    <mx:Application name="FocusManager_setFocus_test"
            xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white"
            creationComplete="focusManager.setFocus(username);">
    

    Peter

  4. You would think this would work but it was unsuccessful for me… I’m only able to set the focus on a text input box by firing it off via a button push. The creation complete doesn’t do it. Very frustrating. And it’s not even the main form in my application so the swf already received focus (I’m using a togglebuttonbar and a viewstack and the text input is on a form that displays after pushing a menu option on the togglebuttonbar) … not sure why the creation complete doesn’t work.

    Ken

  5. show() did not work for me.

    tinput.addEventListener(FlexEvent.UPDATE_COMPLETE, focus);
    
    public function focus(event:Event):void {
        var ti:TextInput = TextInput(event.currentTarget);
        ti.focusManager.setFocus(ti);
    }
    
  6. FocusManager works half for me ..
    It does light up the border around my TextInput but the cursor is not blinking inside nor can I type before actually clicking in the TextInput. This is with use of creationcomplete().
    Show() does nothing :(

  7. Hello,

    One work around for setting initial focus is to manually dispatch an event, like mouse click, then have the event handler set the focus.

    I ran into a tough spot when using the mouse over event to set focus. If you mouse over a component and a wipe plays, when the wipe “reveals” what is underneath, the target/current target becomes what is revealed. When the wipe effect completes, the “curtain” gets the focus again.

    So, in my case, I had to do this:
    var myPoint:Point = new Point();
    myPoint.x = stage.mouseX;
    myPoint.y = stage.mouseY;
    var i:int = (stage.getObjectsUnderPoint(myPoint).length);

    if ( InteractiveObject(stage.getObjectsUnderPoint(myPoint)[i-1].parent).toString()
    !=
    this.toString()
    )
    {
    trace(“setting focus”);
    stage.focus=InteractiveObject(stage.getObjectsUnderPoint(myPoint)[i-1].parent);
    }

    I am relatively new to Flex development, so I do not know if this approach is “good”, but it works!

    Hope this helpls.

    Larry

  8. I am sorry, this is wrong:
    the “curtain” gets the focus again.

    what happens is that the curtain DOES NOT get the focus again. Which is why I had to fire set the focus manually. Otherwise, the subsequent keyboard stroke, which depends on focus, does not occur.

  9. Hello Everyone,

    As this blog has really help me so very much in improving my development skills, I wanted to take the time to solve this issue.

    Here is the solution:

  10. //Set the focus to the Text input field.
    private function setFocusOnStart(event:Event):void
    {
        stage.focus=InteractiveObject(myTextInput);
    }
    
  11. If you want to create a login control that has focus and is waiting for user input when your application firsts starts, there are a few things you need to do.

    1. Inside the HTML page that serves up your SWF file, create a Javascript function that will automatically give the SWF movie focus, and call it from Flex using the ExternalInterface. This is necessary to give the SWF focus in both FireFox and Internet Explorer.

    2. Set focus to the TextInput component. This highlights your TextInput component.

    3. Set the selectionBeginIndex and selectionEndIndex to 0. This puts the cursor in the TextInput control and allows the user to just start typing.

    ********************************************
    So here’s the code to make this all happen!
    ********************************************

    1. Create a Javascript function inside your index.template.html or HTML wrapper file that holds your SWF.

    <script language="JavaScript" type="text/javascript" >
    <!--
    function setFocus()
    {
        window.document.FuelMasterSite.focus();
    }
    
    // -->
    </script>
    

    NOTE: Replace FuelMasterSite with the name of your SWF movie.

    2. Create the MXML Code that will fire an init() method when your application is done loading.

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init(event)" >
    
        <mx:TextInput id="TXI_UserName" />
        <mx:TextInput id="TXI_Password" />
    
    </mx:Application>
    

    3. Create the init() method in Actionscript:

    import flash.external.ExternalInterface;
    import mx.controls.Alert;
    
    private const EMPTY_STRING:String = '';
    
    private function init(event:Event):void {
        if (ExternalInterface.available) {
            ExternalInterface.call('setFocus');
        } else {
            Alert.show("Browser not available");
        }
        focusManager.setFocus(TXI_UserName);
        TXI_UserName.text = EMPTY_STRING;
        TXI_Password.text = EMPTY_STRING;
        LBL_Feedback.text = EMPTY_STRING;
        TXI_UserName.selectionBeginIndex = 0;
        TXI_UserName.selectionEndIndex = TXI_UserName.text.length;
    }
    
  12. Hi Bryan

    Thanks for this. Your solution worked for me.

    Seems like a lot of lines of code to do what you’d think would be a fairly simple task.

    Another thing I thought I’d – I was having trouble getting it to work until I removed the space you had between “<” and “script” in the JavaScript declaration in step 1. Just something that might also trip up other people….

  13. This works fin in Firefox and IE7, however, it does not work in Safari or Chrome.

    Does anyone know how the script can be changed to cater for these browsers.

  14. (ups last post has an error sorry)

    ExternalInterface did not do the job for me, but using navitageToURL did:

    AS3 code

    private function onCreationComplete(event:FlexEvent):void
    {
      // - - all code related to focus of a specific component place it here - -
     
      var u:URLRequest = new URLRequest("javascript:focusFlexApp()");
      navigateToURL(u,"_self");
    }

    Javascript code on ‘index.template.html’

    function focusFlexApp()
    {
      var app = document.getElementById('${application}');
      app.focus();
    }
  15. this is pretty random – but I had to do the same for validators – if invalid then setfocus etc… , so your code worked for me with a minor mod

    focusManager.setFocus(v.source as IFocusManagerComponent);

    M

  16. Nice solution. But you could skip editting the html file with extra javascript by keeping it all in de AS3 code like this:

    navigateToURL(new URLRequest("javascript: document.getElementById('xxx').focus();"), "_self");

    xxx is here the id of your embeded swf

  17. I’ve spent almost an hour on this initial focus issue and finally googled here. Thanks to Bryan and bart for your tips. I got it to work with the following 2 lines of code – tested on FireFox 3.5 and IE 8. init() is set to Application.creationComplete.

    private function init():void {
        navigateToURL(new URLRequest("javascript: document.getElementById('XXXX').focus();"), "_self");
        focusManager.setFocus(textinputID);
    }
  18. FocusManager does not actually keep the focus state. One might assume it does, and implement IFocusManagerComponent interface for somehting other than a UIComponent that needs focus. Walking through the Adobe code, the current focus element is stored in UIComponentGlobals, and is stored not by FocusManager, but by the UIComponent…..

    For example, FocusManager.setFocus(obj) just calls UIComponent.setFocus() which stores the focus state in UIComponentGlobals.

    On non-traditional focus (I am setting focus on a directed graph nodes for accessibility, that is mouse challenged folks that cannot use a mouse and must navigate the graph, we use arrow keys) this implementation is totally bogus. I implemented IFocusManagerComponent on my Sprite, but this is never stored by FocusManager….. I guess I could implement IFocusManagerComponent, but I bet there would be issues down the line, like when I implemented IComponentManager… Sooooo looks like I have to roll my own.

  19. Just a quick note that helped me – I was having trouble getting focus on a text input in the new title window I was popping up. I think something was stealing focus after I used textInput.setFocus(); So to solve this I just used the callLater() declaration;

    private function onCreationComplete(event:FlexEvent):void
    {
         //call on screen refresh instead of right NOW!
          callLater( setTextInputFocus);
    }
     
    private function setTextInputFocus():void
    {
         textInput.setFoucs();
    }
  20. Thanks for input here guys. Annoying little problem, nicely solved. Went with Tong’s solution.

  21. I’ve tried every solution posted here and all i can get to work is for the app to set the focus on the textinput without being able to type.
    I do not have my app inside a html so i dont need the whole setting focus to the app but only for the textinput. The one thing everyone seem to have in common is focusManager.setFocus(ID; and that seem to only do what i’ve just described mine does..

    Any ideas? Bryans solution did not do squat either =/

    1. EDIT: I completely missed out on the part where i had to add the javascript to my index.template *facepalm*
      Thank you, Bryans code worked excellent!

  22. I have form by inputtext controls, but they depend on each other,
    you may fill one field and when click to another one code search for what is has filled, just like validation,
    in this case, form is refreshed for millisecond,, event cant see, but unfortunately, user missed the control which he wanted to click,
    (ex: fill the name field and when go to address field) what i need is when validation is done, i need to focus and pint the cursor to particular control which used clicked,

    none of above worked for me, but
    drawFocus(true) this worked me, without cursor pointing to control.

    any one has idea,

  23. I have the following:

    - menu.mxml : is application, and main application in the proyect
    In the menu.mxml contain:


    ...
    public function doLogin():void{
    loginForm = login(PopUpManager.createPopUp(this, login, true));
    PopUpManager.centerPopUp(loginForm);
    loginForm.ventanaPadre = this;
    loginForm.edUsuario.setFocus();
    }
    ...

    - login.mxml is a titlewindows called from menu.mxml in creationcomplete event
    In the login.mxml contain:


    "
    ...


    <fx:Script ...
    ...
    protected function init(event:Event):void{
    navigateToURL(new URLRequest("javascript:document.getElementById('menu').focus();"), "_self");
    focusManager.setFocus(edUsuario);
    }
    ...

    the application works fine.

    thank.

    fernando

  24. Ok, so after an hour of research. I found this site: http://www.flexjunk.com/2010/12/30/managing-initial-swf-focus-in-all-browsers/

    Basically all you need to do is add this line to your index.template.html:
    params.wmode = “opaque”;

    Then add this function to your flex app and call it from creationComplete=”init(event)”:

    protected function init(event:Event):void
    {
    //set focus to this app using javascript
    if(ExternalInterface.available)
    {
    ExternalInterface.call("eval", "document.getElementById('" + ExternalInterface.objectID + "').tabIndex=0");
    ExternalInterface.call("eval", "document.getElementById('" + ExternalInterface.objectID + "').focus()");
    //This is where you would add your focus statement
    username.setFocus();
    }
    }

  25. Sigh. This stuff is pathological.

    The Flex framework needs to address this internally if it is to be an enterprise solution.

    (Calling JS to set focus inside a Flex app? Madness…)

  26. So it looks like none of these methods works in Chrome 14.0.835.94 beta or in Opera 11.50, although it is working for me now in Explorer 8.0.6, Firefox 4.0.1, and Safari 5.0.5. Any new ideas to get focus in these browsers? Mainly Chrome, I browse in Chrome so I’d love my apps to work the way I want them to in Chrome.

  27. Nathan’s method works for me with FF (3.6), IE (8.0), Chrome (14.0), and Safari (5.0.4).

    The NavigateToURL one-liner method from further above also worked, but in some cases it interfered with the use of SWFAddress, so just wanted to mention that. The ExternalInterface calls work seamlessly with SWFAddress.

    Thanks to all for the great tips.

  28. I got setFocus to work ie being able to type, tab and get focus rectangle to draw on a text control by setting the focus to the text Input field textDisplay like this:

    focusManager.setFocus(textInput_userName.textDisplay);
    textInput_userName.textDisplay.selectRange(textInput_userName.text.length, textInput_userName.text.length);

    I am using Air so not sure how it works in all the different browsers…

  29. u also edit the html code in the html-libs dir in ur project.thts wrks well..
    In tht
    xxx is the swf name by defalt @application is tht name……

    1. body tag set the body onload in ur flash object.focus(),document.getElementById(‘@application’).focus()..this will wrks well

Comments are closed.