Search code examples
backbone.jschaplinjs

Chaplin no context after template rerender


I'm trying to have a view which can have interchangable templates. So clicking on one of the checkbox rerenders the view. this in fact is happening . but after the view has rerenderd and show the new template correctly im loosing the context and all click bound to this view don't work anymore. http://pastebin.com/bFJ5Yuer

View = require 'views/base/view'
template = require 'views/templates/list_view_a'

module.exports = class OfferListView extends View
autoRender: true
container: "[data-role='content']"
containerMethod: 'html'
   initialize: ->
    super
    @template = template
    #views
    @delegate 'change', '#list_view_a', @change_list_view
    @delegate 'change', '#list_view_b', @change_list_view
    @delegate 'change', '#list_view_c', @change_list_view
    @delegate 'click',  @click_ev

change_list_view: (event) =>
    console.log('change')
    @template = require 'views/templates/' + event.target.id
    @render()

click_ev: =>
    console.log('click')

getTemplateData: =>
    @collection.toJSON()

Any pointers ?


Solution

  • Yeah, the call to @render in change_list_view is wiping out the element that the events are bound to in the initialize method.

    If you must re-render the view (like if you are changing the template) then you will just have to add a call to @delegateEvents below the @render call in change_list_view.

    UPDATE

    If you wanted to switch to a subview method, you could probably get rid of that second call to render. Something like this:

    # snipped all the outer require js stuff
    
    class InnerViewBase extends Chaplin.View # Or whatever your base view is
      autoRender: true
      container: "#innerViewContainer"
      containerMethod: "html"
    
      initialize: (templateName) ->
        @template = require templateName
    
        super
    
    class ListViewA extends InnerViewBase
      initialize: ->
        super "views/templates/list_view_a"
    
        # Do any event handlers in here, instead of the outer view
        # @delegate 'click',  @click_ev
    
    class ListViewB extends InnerViewBase
      initialize: ->
        super "views/templates/list_view_b"
    
    class ListViewC extends InnerViewBase
      initialize: ->
        super "views/templates/list_view_b"
    
    class OfferListView extends View
      autoRender: true
      container: "[data-role='content']"
      containerMethod: 'html'
    
      initialize: ->
        super
        @template = template
    
        #views
        # Consider changing these three id subscriptions to a class
        @delegate 'change', '#list_view_a', @change_list_view
        @delegate 'change', '#list_view_b', @change_list_view
        @delegate 'change', '#list_view_c', @change_list_view
        @delegate 'click',  @click_ev
    
      afterRender: ->
        # Add a default ListView here if you want
        # @subview "ListView", new ListViewA
    
      change_list_view: (event) =>
        console.log('change')
    
        # Make a hacky looking map to the subview constructors
        viewNames = 
          "list_view_a": ListViewA
          "list_view_b": ListViewB
          "list_view_c": ListViewC
    
        @subview "ListView", new viewNames[event.target.id]
    
      click_ev: =>
        console.log('click')
    
      getTemplateData: =>
        @collection.toJSON()