Submit a Knockout-Bound jQuery Dialog when Enter is Pressed

There I was, happily coding an awesome logon prompt using the technique previously discussed here, when I ran into a problem: my form wasn’t submitting when I pressed the ‘enter’ key. That’s annoying. No self-respecting logon prompt should require you to move the mouse to a button and click!

So what to do?! Step one: don’t panic. Okay, good. Now you can use a few easy tricks to force the dialog to submit when enter is pressed.

Let’s look at the example that doesn’t work. I have a simple Knockout view model hooked up to a jQuery dialog. When I click the dialog’s “Login” button, it calls a login function. If I press the enter key, though, nothing happens. I take that back; one thing happens: you become annoyed that nothing happened.

var loginViewModel = function() {
    var self = this;
    self.password = ko.observable();
    self.username = ko.observable();
};

$("#loginDialog").dialog({
    buttons: {
        "Login": login
    }
});

function login() {
    // login stuff
}
<div id="loginDialog" title="Login">
    <form id="loginForm">
        <fieldset>
            <label for="user">Username</label>
            <input type="text" id="user" data-bind="value: username" />
            <label for="password">Password</label>
            <input type="password" id="password" data-bind="value: password" />
        </fieldset>
    </form>
</div>

The first thing we need to do is to bind our form to our view model using Knockout’s submit binding. With the submit binding in place, we can use jQuery to submit the form.

var loginViewModel = function() {
    var self = this;
    self.password = ko.observable();
    self.username = ko.observable();
    self.login = function() {
        // login stuff
    };
};

$("#loginDialog").dialog({
    buttons: {
        "Login": function () {
            $("#loginForm").submit();
        }
    }
});
<div id="loginDialog" title="Login">
    <form id="loginForm" data-bind="submit: login">
        <fieldset>
            <label for="user">Username</label>
            <input type="text" id="user" data-bind="value: username" />
            <label for="password">Password</label>
            <input type="password" id="password" data-bind="value: password" />
        </fieldset>
    </form>
</div>

Now we’re equipped to handle the enter keypress. So let’s do that…

var loginViewModel = function() {
    var self = this;
    self.password = ko.observable();
    self.username = ko.observable();
    self.login = function() {
        // login stuff
    };
};

$("#loginDialog").dialog({
    buttons: {
        "Login": function () {
            $("#loginForm").submit();
        }
    }
});
$("#loginDialog").keypress(function(event) {
    if (event.which == 13) {
        event.preventDefault();
        $("#loginForm").submit();
    }
});

That might seem like that should be it, but it’s not quite working. It seems to submit just fine, but login only succeeds when the button is pressed. What gives!? It’s a subtle thing that took me a little bit of time to realize. Databound values are only updated by default when focus leaves the control. So, if you enter a username, press tab, enter a password, then press enter, the password value in the view model hasn’t been updated yet! Argh!

No problem, though. We can change the value to update with each keypress.

<div id="loginDialog" title="Login">
    <form id="loginForm" data-bind="submit: login">
        <fieldset>
            <label for="user">Username</label>
            <input type="text" id="user" data-bind="value: username, valueUpdate: 'afterkeydown'" />
            <label for="password">Password</label>
            <input type="password" id="password" data-bind="value: password, valueUpdate: 'afterkeydown'" />
        </fieldset>
    </form>
</div>

Now we’re in business! The login works great whether you press the button or use the enter key.

Advertisement

Author: Adam Prescott

I'm enthusiastic and passionate about creating intuitive, great-looking software. I strive to find the simplest solutions to complex problems, and I embrace agile principles and test-driven development.

Leave a comment

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 )

Facebook photo

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

Connecting to %s

%d bloggers like this: