bisgardo
bisgardo

Reputation: 4600

Give focus to first form element inside a jQueryUI Dialog

I have a login form, fetched with AJAX, that I want to display in a jQuery UI Dialog, and want the first input field to have autofocus. I have got it working using the code below, but I find it to be quite a hack, and think there ought to be a nicer solution. Also, the behavior seems consistent over Chrome 23, IE9, and Firefox 16, so I would like to take the opportunity to get a bit deeper understanding of this stuff, and hope someone is willing to shed some light.

I have found many related questions here on SO and other places, but none of the proposed answers seems to work for me. Curiously, many of the questions were on the opposite problem; namely removing autofocus...

The form fetching etc. is triggered by the keys Alt+l using the jQuery Hotkey plugin. The first input element has id 'user'. The code is

$(document).bind('keydown', 'Alt+l', function () {
    $('<div>', {
        title: 'Log in'
    }).load('?action=login').dialog({
        modal: true,
        show: 'fade',
        hide: 'fade',
        resizable: false,
        draggable: false,
        open: function (e) {
            // Hack alert!
            setTimeout(function () {
                $('input:first', e.target).focus();
            }, 100);
        }
    });
    //$('#user').focus(); <- won't work; $('#user').length == 0
});

The thing I don't understand is why I have to put the focus() call inside a timeout for this to work. The selection $('input:first', e.target) (or the equivalent, commented out, $('#user')) is empty if the selection is not deferred by the timeout.

If anyone can explain this behavior, or perhaps give a better solution, it would be much appreciated!

Update

The fetched HTML is just a regular form

<form action="?action=login" method="post">
    <table>
        <tr><td><label for="user">Username:</label>
            <td><input id="user" type="text" name="user">
        <tr><td><label for="pass">Password:</label>
            <td><input id="pass" type="password" name="pass">
        <tr><td><td><input type="submit" value="Log in">
    </table>
</form>

Note that the response on the URL ?action=login is different on GET and POST requests

Upvotes: 2

Views: 1387

Answers (1)

bisgardo
bisgardo

Reputation: 4600

I think the problem is that I create the dialog too ealy; before load is completed. So moving the dialog code inside a callback to load works without the delay:

$(document).bind('keydown', 'Alt+l', function () {
    $('<div>', {
        title: 'Log in'
    }).load('?action=login', function () {
        $(this).dialog({
            modal: true,
            show: 'fade',
            hide: 'fade',
            resizable: false,
            draggable: false,
            open: function () {
                $('input:first', this).focus();
            }
        });
    });
});

I thought that load was synchronous, and that it therefore wouldn't matter where the selection $('input:first', this) was made, but that seems not to be the case.

It may also be that all that was needed was to put the selection in a separate event in order for the DOM to update properly after the event handling conaining load is completed. In that case, the two solutions are essentially equivalent, except the former being an ugly hack and the latter not so.

If any of this is nonsense, please do not hesitate to correct me.

Upvotes: 2

Related Questions