I have a view called DashboardView
that instantiates multiple WidgetView
s. Each widget needs to have its own event bindings. So far as I can tell, these bindings get lost when the view is rendered and added to the parent view, i.e.:
class DashboardView extends Backbone.View
constructor: ->
context = @
_.each @collection, (w)->
dv = new app.WidgetView(model: w)
context.$el.append(dv.render())
class WidgetView extends Backbone.View
events:
"click .config" : "config_widget"
render: ->
_.template($("#widget-template").html(), @model)
Doing it this way, the click events on the .config
element of the widget are now lost. Is there a better way of mixing the nested views into the parent while ensuring that the event handlers on the child view are channelled correctly?
One solution I have seen to this problem comes in this article. This looks about right, but I'm curious if there is a more elegant way of solving this.
Try this:
class DashboardView extends Backbone.View
constructor: ->
@collection.each ( w ) =>
dv = new app.WidgetView( model: w )
@$el.append dv.render().el // Append widget's @el explicitly
class WidgetView extends Backbone.View
tagName: 'div' // or whatever your view's root element is
template: _.template $( "#widget-template" ).html() // pre-compile template
events:
"click .config": "config_widget"
render: ->
@$el.html @template @model.toJSON() // append template to @el
return this // return view
So, the idea is this:
(1) Inside the WidgetView
's render
method, you populate @el
(the root element of the view) with its model's data via the template. (And notice how I compile the template only once - there is no need to compile the template on each render operation.)
(2) Inside the DashboardView
, you append the widget's root element - @el
- to the DOM.
The thing is that the view's events delegate to its root element - @el
. Therefore, you want to work with the root element explicitly: inside render
, you populate it, and then you append it to the DOM.
Your issue is that delegateEvents
expects a single, non-changing element for your view. Because your render
function creates a new element every time, the bindings made by delegateEvents
are never fired when you click on the element generated by render
.
Luckily the current version of Backbone offers a setElement
method that will reassign your element with the argument you provide, and then it will automatically call delegateEvents
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With