How to automatically focus first backbone-forms input field?

5.1k views Asked by At

The following screenshot shows a combined form for sign-in and sign-up:

Backbone Form

The following module is used to render the AuthView:

MyApp.module("User", function(User, App, Backbone, Marionette, $, _) {

  User.AuthView = Marionette.ItemView.extend({

    className: "reveal-modal",
    template: "user/auth",

    ui: {
      signInForm: "#signin-form",
      signUpForm: "#signup-form"
    },

    events: {
      "focus input": "onFocus"
    },

    onFocus: function() {
      console.log("Some input field has received focus.");
    },

    onRender: function() {  
      this.signInForm = new Backbone.Form({
        schema: {
          signInEmail: { 
            type: "Text", 
            title: "E-Mail address"
          },
          signInPassword: { 
            type: "Password", 
            title: "Password"
          }
        }
      }).render();
      this.ui.signInForm.prepend(this.signInForm.el);

      this.signUpForm = new Backbone.Form({
        schema: {
          signUpEmail: { 
            type: "Text", 
            title: "E-Mail address"
          },
          signUpPassword: { 
            type: "Password", 
            title: "Password"
          },
          signUpPasswordConfirmation: { 
            type: "Password", 
            title: "Password confirmation"
          }
        }
      }).render();
      this.ui.signUpForm.prepend(this.signUpForm.el);
    }

  });
});

How can I automatically focus the first field in each sub-form whenever it is rendered? The first fields would be signInEmail for the signInForm and signUpEmail for the signUpForm.
I tried to listen to focus input events. Such an event is triggered when I click into one of the input fields, not before.


Meanwhile, inspired by the current answers I came up with the following helper function:

focusFirstFormField: function(form) {
  if (_.isUndefined(form)) {
    throw "IllegalStateException: Form is undefined."
  }
  // TODO: AuthView does not focus first sign-in field.
  var firstInput = form.find(':input:first');
  if (_.isObject(firstInput)) {
    if (firstInput.length > 0) {
      firstInput = firstInput[0];
    }
    else {
      throw "IllegalStateException: Form find returns an empty jQuery object."
    }
  }
  _.defer(function() {
    firstInput.focus();
  });
 }

There is still need for improvement, though.

4

There are 4 answers

1
Evan Hobbs On

The events object are DOM events which are generally triggered by the user so that's not what you'll likely want to use in this case.

If I'm understanding you correctly you would like to put the focus in the first input of each of the forms but since you can only have focus on one thing at a time and they are rendering together you'll have to choose one or the other.

The simplest option is to add another line at the end of onRender focusing on the input. If your input is generating an input something like this:

<input type="text" name="signInEmail">

Then you can add:

this.$('[name=signInEmail]').focus();

If not you'll have to change the selector this.$(xxxx).focus() to suit.

3
Billy Chan On

You can use onDomRefresh event of the view. It will be triggered after view rendered and Dom refreshed.

onDomRefresh: function() {
  this.focusFirstInput();
};

focusFirstInput: function() {
  this.$(':input:visible:enabled:first').focus();
};

This solution applies to general cases. However, pay attention if you are using Bootstrap. I can't get this work there. Instead, I set autofocus: 'autofocus' in the field and it works.

1
user2503775 On

You can add it to onRender method.

this.ui.signInForm.find('input[type=text]:first').focus();
this.ui.signUpForm.find('input[type=text]:first').focus();
0
firebird631 On

On the onRender method I do :

$(this.el).find(':input[autofocus]').focus();

And I add the autofocus="" flag onto my HTML node. This works for refresh.