9
votes

I have a backbone view that creates a new div for each model that is passed into it. However, I cannot get any sort of events to fire (click a.change-status) on the view and I assume it's because the elements inside of it are also generated from a template. Please let me know if there's some way around this.

var videoDivView  = Backbone.View.extend({
el: '<div class="vendor-video" />',
initialize: function(){
    _.bindAll(this);
    this.render();
    this.model.on('change:published', this.enableSaveButton);
},
events: {
    'click a.change-status'     : 'changeVideoStatus'
},
template: video_tmpl,
render: function(){
    this.$el.attr("id", 'video-'+this.model.id);
    this.$el.html(this.template(this.model.toJSON()));
    this.$el.data('status', video_statuses[this.model.get('published')]);
},
changeVideoStatus: function(e) {
    console.log(this.model);
    return false;   
}, 
enableSaveButton: function() {
    $('#save-changes').removeClass('disabled').removeAttr('disabled');
}
});

an example template would look like:

<script id="single-video-tmpl" type="text/x-jquery-tmpl">
<div>
    <div class="video-info">
        <span class="video-title"><%=video_title%></span>
        <div class="bottom-info">
            <a href="#<%=id%>" class="change-status"></a>
        </div>
    </div>

</div>
</script>
4
the el attribute you're setting doesn't make sense, it should be a jquery like selector (api.jquery.com/category/selectors). - gitaarik
I'm having it create a div for each model - Drew Bartlett
Oh, does that work? I've never seen it used like that to be honest, sorry. - gitaarik
That's okay. Yes, it works great that way depending on what you're trying to accomplish. - Drew Bartlett
I think it might be because the element is only created after it has initialized. So at initialization (where the events object is parsed) it can't bind the click events to any element in the DOM. - gitaarik

4 Answers

8
votes

There are some things that might be the cause of the problem.

First of all, your el declaration seems to be suspect. If you want a div with that class you just have to define the className attribute since the default for backbone views is div.

Instead of: el: '<div class="vendor-video" />'

just use: className: 'vendor-video'

I don't see any details about your view initialization methods but the best practice is to initialize a view and then render it to the container:

var yourVideoDivView = new videoDivView({model: model});
$("#your-video-container").html(yourVideoDivView.render().el)

also to get the last line work you have to return this; on your render method.

render: function(){
  ...
  return this;
}

About using this.delegateEvents(), you should call this function after your view is already in the DOM otherwise it makes no sense. ie:

$("#your-video-container").html(yourVideoDivView.render().el)
yourVideoDivView.delegateEvents();

delegateEvents() will makes your view events alive again.

12
votes

Try a this.delegateEvents() after you render the new content.

1
votes

I had a similar problem. You can resolve this problem in two steps.
- Create a tagName in view
- Append your template in this.$el
That's all. And it work without this.delegateEvents()

0
votes

The issue I observed with tagName and appending using this.$el is, the event listener failed to attach the event for the last element created with selected tagName. But, the problem got solved when using this.delegateEvents() after appending the elements to DOM.