javascripthtmlbackbone.jsbackbone-events

OnBlur event in backbone


I am using the blur action with backbone. In my backbone view I have

var EventView = Backbone.View.extend({

    tagName:  "li",

    template: _.template($('#item-template').html()),

    events: {
      "click .toggle"   : "toggleDone",
      "dblclick .view"  : "edit",
      "click a.destroy" : "clear",
      "keypress .edit"  : "updateOnEnter",
      "blur .edit"      : "close"
    },

    initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.remove);
    },

    render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      this.$el.toggleClass('done', this.model.get('done'));
      this.form = this.$(".edit");
      this.input = this.$(".edit-title");
      this.eventLeaders = this.$('.edit-leaders');
      this.eventDescription = this.$('.edit-description');
      return this;
    },

    toggleDone: function() {
      this.model.toggle();
    },

    edit: function() {
      this.$el.addClass("editing");
      this.form.focus();
    },

    close: function() {

      if (!this.input.val()) {
        this.clear();
      } else {
        this.model.save({
                    title: this.input.val(), 
                    description: this.eventDescription.val(),
                    leaders: this.eventLeaders.val().split(/[, ]+/)});
        this.$el.removeClass("editing");
      }
    },

    updateOnEnter: function(e) {
      if (e.keyCode == 13) this.close();
    },

    clear: function() {
      this.model.destroy();
    }

});

In my HTML I have:

  <script type="text/template" id="item-template">
    <div class="view">
      <input class="toggle" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
      <label><%- title %></label>
      <div class="details">
        <span class="description"><p><%- description %></p>Leaders:</span>
        <% _.each(leaders, function(leader){ %>
          <span class="event-leader"> <%= leader %> </span>
        <% }); %>
      </div>
      <a class="destroy"></a>
    </div>
    <form class="edit">
      <input class="edit-title" type="text" value="<%- title %>" />
      <input class="edit-description" type="text" value="<%- description %>" />
      <input class="edit-leaders" type="text" value="<%= leaders.join(', ') %>" />
    </form>
  </script>   

and in my CSS I have:

#event-list li.editing .edit {
    display: block;
    width: 444px;
    padding: 13px 15px 14px 20px;
    margin: -30px;
}

#event-list li.editing .view {
    display: none;
}
#event-list li .edit {
    display: none;
}

The problem I have is the blur event is fired when I switch between editing different textboxes and I am not sure why. Even when I use tab to switch between text boxes. I don't want this to be the default behavior. How can I change this?


Solution

  • If there is a selector in your events -hash like this

    'blur <the event designator> .edit <the selector>': 'onBlur'
    

    The backbone.js delegateEvents uses the jQuery on -function to bind events like this

    this.$el.on(eventName, selector, method);
    

    However, there's a gotcha, that can be found from the jQuery docs on the on -function and its parameters

    selector

    Type: String

    A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element.

    Somehow when the selector is included, the eventhandler catches the events propagating from the children of the element (in this case the inputs). Without the selector, the events are not caught (i made a fiddle to demonstrate, open your console and toggle the different inputs). Quick playing around with my fiddle also revealed it to be nigh impossible to detect wether or not the form had focus.

    This is why the blur event is triggered by the input fields. As to how to detect when your form loses focus: it is hard to say, because browsers decide for themselves, which elements they allow focus to be given to. Here are some stackoverflow sources i found, but failed to get to work in the fiddle:

    Using jQuery to test if an input has focus

    When onblur occurs, how can I find out which element focus went *to*?