Setting focus in Flex using the Focus Manager

by Peter deHaan on September 23, 2008

in FocusManager

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>

{ 22 comments… read them below or add one }

1 Inca September 23, 2008 at 11:44 pm

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.

Reply

2 peterd September 24, 2008 at 7:33 am

And as a reminder, if you do encounter bugs with the Flex SDK (or Flex Builder, Flex Documentation, Flash Player, etc), the best place to report them is http://bugs.adobe.com/flex/ .

Peter

Reply

3 time2design October 6, 2008 at 1:32 pm

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

Reply

4 peterd October 6, 2008 at 11:48 pm

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

Reply

5 OneWorldMedia November 9, 2008 at 4:27 pm

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

Reply

6 Terroso.Costa January 26, 2009 at 2:50 am

Hi OneWorldMedia, try to use the show() method instead of creationcomplete.

Cheers,

Rui

Reply

7 ra February 8, 2009 at 7:01 pm

Hi Terroso.Costa, I have tried to use to the show() method instead of creationcomplete. But not success.

Reply

8 ropo February 9, 2009 at 3:03 am

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);
}

Reply

9 jurlan March 14, 2009 at 4:31 am

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 :(

Reply

10 Larry March 26, 2009 at 1:50 pm

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

Reply

11 Larry March 26, 2009 at 1:52 pm

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.

Reply

12 Larry March 27, 2009 at 3:33 pm

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:

Reply

13 Larry March 27, 2009 at 3:34 pm
//Set the focus to the Text input field.
private function setFocusOnStart(event:Event):void
{
    stage.focus=InteractiveObject(myTextInput);
}

Reply

14 Bryan Clover April 7, 2009 at 6:50 am

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;
}

Reply

15 Chris April 11, 2009 at 12:40 pm

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….

Reply

16 Tim May 7, 2009 at 7:36 am

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.

Reply

17 Acatl May 18, 2009 at 3:26 pm

(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();
}

Reply

18 Arnold Aprieto June 3, 2009 at 1:05 pm

Thanks Bryan. Your solution is exactly what I was looking for.

Reply

19 mike October 28, 2009 at 10:42 pm

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

Reply

20 bart November 18, 2009 at 6:39 am

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

Reply

21 Tong Wang December 10, 2009 at 11:15 pm

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);
}

Reply

22 LarryG January 20, 2010 at 11:22 am

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.

Reply

Leave a Comment

Sorry, this blog is terrible at eating HTML comments.
If you're pasting any HTML/XML/MXML code, you need to convert your < characters to &lt; and your > characters to &gt; .

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Anti-Spam Protection by WP-SpamFree

Previous post:

Next post: