Reputation: 9220
I've seen this issue crop up a few times but haven't been able to solve it myself- or I don't quite understand the answers. Many things talk about using .empty().append()
rather than .html()
and stuff about making sure to always refer to the view's $el
value rather than directly accessing the DOM. Still no dice.
If you take a look at this jsbin, you'll see that changing the select box value re-renders the wrapper view the first time, but then does nothing on subsequent changes- it loses its events.
http://jsbin.com/fuvoba/7/edit (apologies to any coffeescript haters)
Any idea why this could be happening?
Many thanks and internet pints in advance, as always :)
class ArchivesDropdownView extends Backbone.View
template: '<select><option>One</option><option>Two</option></select>'
initialize: () ->
console.log 'Initialised the select dropdown'
render: () ->
this.$el.find('#dropdown').empty().append @template
console.log 'Rendered the select dropdown'
return this
events:
'change select': 'updateSelect'
updateSelect: () ->
console.log 'Updated select dropdown.'
wrapperView.render()
class WrapperView extends Backbone.View
template: 'Please select: <div id="dropdown"></div><div id="random"><%=randomNum%></div>'
render: () ->
console.log 'Rendered the wrapper'
this.$el.empty().append _.template(@template)(randomNum: Math.random())
if !this.archivesDropdownView
this.archivesDropdownView = (new ArchivesDropdownView().render())
this.archivesDropdownView.render()
return this
wrapperView = new WrapperView()
$('body').empty().append wrapperView.render().$el
Upvotes: 1
Views: 249
Reputation: 1553
Add this.archivesDropdownView.delegateEvents()
after appeding view $el
to the other view.
this.$el.find('#dropdown').empty().append this.archivesDropdownView.$el
this.archivesDropdownView.delegateEvents()
But I don't like your architecture, you should use global reference from child view to render parent view. Use events instead, for example share the model between parent and child views and trigger event from child view to re-render parent view.
Here is a working example http://jsbin.com/dehujecejape/1/edit
Upvotes: 3
Reputation: 5625
You have this kind of problem because you don't do things the way they are supposed to be done. Why would you re-render entire container when one of its components change? Of course you will have all kinds of troubles with this approach.
I'd recommend you create a third component, and update it on select box change:
class ArchivesDropdownView extends Backbone.View
template: '<select><option>One</option><option>Two</option></select>'
initialize: (opts)->
console.log 'Initialised the select dropdown'
@listener = opts.listener
render: ->
console.log 'Rendered the select dropdown'
@$el.html @template
events:
'change': 'updateSelect'
updateSelect: ->
@listener.render()
class RandomGeneratorView extends Backbone.View
template: '<%=randomNum%>'
render: ->
@$el.html _.template(@template)(randomNum: Math.random())
class WrapperView extends Backbone.View
template: 'Please select: <div id="dropdown"></div><div id="random"></div>'
initialize: ->
console.log "wrapper init"
randomElement = new RandomGeneratorView()
@randomGeneratorView = randomElement.render()
@archivesDropdownView = (new ArchivesDropdownView(listener: randomElement)).render()
render: ->
@$el.html @template
@randomContainer = @$el.find "#random"
@dropdownContainer = @$el.find "#dropdown"
@dropdownContainer.html @archivesDropdownView
@randomContainer.html @randomGeneratorView
@$el
$('body').html (new WrapperView()).render()
Here's a modified JSBin
Upvotes: 1