JJD
JJD

Reputation: 51874

How to automatically focus first backbone-forms input field?

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.

Upvotes: 3

Views: 5116

Answers (4)

firebird631
firebird631

Reputation: 569

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.

Upvotes: 1

user2503775
user2503775

Reputation: 4367

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

Upvotes: 1

Billy Chan
Billy Chan

Reputation: 24815

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.

Upvotes: 4

Evan Hobbs
Evan Hobbs

Reputation: 3672

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.

Upvotes: 6

Related Questions