dopatraman
dopatraman

Reputation: 13908

Backbone events not firing, no errors and element exists

Template:

<div class="view">
  <input id="todo_complete" type="checkbox" <%= completed ? 'checked="checked"' : '' %> />
  <label><%= title %></label>
  <button class="destroy"></button>
</div>
<input class="edit" value="<%= title %>" />

View:

var TodoView = Backbone.View.extend({
  tagName: 'li',

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

  events: {
    'dblclick label': 'edit',
    'keypress .edit': 'updateOnEnter',
    'blur .edit': 'close'
  },

  initialize: function() {
    console.log('Todo View initialized!');
    this.$el = $('#todo');
    console.log(this.$el);
    this.render();
  },

  render: function() {
    console.log('Todo View render started...');
    console.log(this.model.attributes);
    this.$el.html(this.todoTpl(this.model.attributes));
  },

  edit: function() {console.log('edit called!');},

  close: function() {console.log('close called!');},

  updateOnEnter: function(e) {
    console.log(e);
  }
});

There are no events when the page loads, and I'm able to see the rendered template. However if I double click on the label, keypress on the input or blur the other input, nothing happens. I'm expecting to see a log in the console. What am I doing wrong?

Upvotes: 1

Views: 204

Answers (2)

mu is too short
mu is too short

Reputation: 434685

You lose your event bindings when you:

this.$el = $('#todo');

You're not supposed to directly assign to the $el or el properties, you're supposed to call setElement instead:

setElement view.setElement(element)

If you'd like to apply a Backbone view to a different DOM element, use setElement, which will also create the cached $el reference and move the view's delegated events from the old element to the new one.

Also, if you're going to be changing the view's el then there's no need for a tagName property. You could also specify the el when you create the view:

new TodoView({ el: '#todo' });
new TodoView({ el: $('#todo') });

If your #todo is actually the <ul> or <ol> then:

  1. Leave the tagName alone.
  2. Add the view's el to $('#todo') by calling append instead of calling setElement.

If this is the case then your code would look more like this:

var TodoView = Backbone.View.extend({
  tagName: 'li',
  //...
  initialize: function() {
    console.log('Todo View initialized!');
    this.render();
  },
  //...
});

// And then where you create the view...
var v = new TodoView(...);
$('#todo').append(v.el);

Upvotes: 1

dopatraman
dopatraman

Reputation: 13908

So I was able to solve this problem by adding el to the properties passed into Backbone.View:

 var TodoView = Backbone.View.extend({
  tagName: 'li',

  // ...
  el: $('#todo')
  // ..
});

Upvotes: 0

Related Questions