andrewmart.in
andrewmart.in

Reputation: 1703

Correct use of Backbone listenTo from within view; Marionette region is undefined?

This is related to another question I posted here, but it's still boggling my mind.

I have a simple backbone model instance, called searchResult that I have working great within my view.

What I'm basically trying to do is simple; reset the an area of content inside the view as this model changes.

For some reason, when I'm inside a the view, this code doesn't seem to work correctly, though it seems it should:

View Code:

define [
      'backbone.marionette',
      "jquery",
      "underscore",
      "backbone",
      'text!globalTemplates/sidebar.html',
      "global/models/sidebar",
      "global/views/categories",
      "global/collections/categories",
      "global/views/stores",
      "global/collections/stores",
      'search/models/search-results'
    ], (Marionette, $, _, Backbone, SidebarTemplate, SidebarModel, categoriesView, categoriesCollection, storesView, storesCollection, SearchResult) ->
      class SidebarLayout extends Marionette.Layout

        template:                 _.template SidebarTemplate
        id:                       'sidebar'
        className:                'js-sidebar marionette-layout'
        tagName:                  'aside'

        regions:
          form:                   'form'
          categoriesList:         '#categories-list'
          storesList:             '#stores-list'

        ui:
          searchInput:            "input.search"
          logo:                   "strong#logo a"
          lower:                  ".lower"
          top:                    ".top"

        events:
          "click strong#logo a":  "goHome"
          "submit .top form":     "search"
          "click button.submit":  "search"
          # "keyup input.search":   "quickSearch"

        initialize: (opts) ->
          @router = opts.router

          # event triggers
          @on "sidebar:finished", @resize, @

          # override the categories display event
          @categoriesList.open = (view) ->
            this.$el.hide()
            this.$el.html(view.el)
            this.$el.slideDown(250, "easeOutExpo")

          # override the stores display event
          @storesList.open = (view) ->
            this.$el.hide()
            this.$el.html(view.el)
            this.$el.slideDown(250, "easeOutExpo")

          # override the categories remove event
          @categoriesList.remove = (view) ->
            this.$el.html(view.el)
            this.$el.slideUp(250, "easeOutExpo", -> $(this).remove())

          # override the stores display event
          @storesList.remove = (view) ->
            console.log 'stores remove'
            this.$el.slideUp(250, "easeOutExpo", -> $(this).remove())

        globalListeners: ->

          # bind app vent and other global handlers
          # app.vent.on "search:setParams", @setSearchInput

          # SearchResult.on "change:params", @setSidebar, @

          # bind to changes to search params.
          # SearchResult.listenTo @, "change:params", @setSidebar()
          SearchResult.listenTo @, "change", @setSidebar()
          # SearchResult.on "change:params", @render, @

        resize: =>
          sidebarHeight = @$el.height()
          topHeight     = @ui.top.height()
          @ui.lower.height(sidebarHeight - topHeight)

        setSidebar: (input=true) =>
          # console.dir "SidebarLayout: setSidebarContent"
          if input then @setSearchInput()

          if SearchResult.get("params")
            switch SearchResult.get("params").type
                when "categories"
                  @setCategories()
                when "text"
                  @setStores()
                  @setCategories()

        setSearchInput: ->
          if SearchResult.get("params")?
            searchTerm = SearchResult.get("query")
            @ui.searchInput.attr("value", searchTerm)
          else
            @ui.searchInput.attr("value", "")

        setStores: ->
          stores = new storesCollection()
          stores.fetch
            success: =>
              @storesView = new storesView
                collection: stores
              @storesList.show @storesView
              @storesList.$el.prev("h3").show()
              @trigger "sidebar:finished"

        setCategories: ->
          # console.log 'SidebarLayout: setCategories'
          categories = new categoriesCollection()
          categories.fetch
            success: =>
              @categoriesView = new categoriesView
                collection: categories
              @categoriesList.show @categoriesView
              @categoriesList.$el.prev("h3").show()
              @trigger "sidebar:finished"

        reset: =>
          @$el.css
            "opacity": 0
            "margin-left": "-500px"

        slideSidebarIn: =>
          @$el
          .animate
            "opacity":1
            "margin-left":0
          , 500, -> app.reqres.setHandler "sidebar:visible", -> true

        # CUSTOM EVENTS

        goHome: (e) =>
          e.preventDefault()
          # @router.navigate "/", trigger: true
          # we're going to avoid using navigate,
          # too complex to refactor at this point
          window.location = "/"

        quickSearch: =>
          # not working yet.
          value = @ui.searchInput.val()
          SearchResult.set("value", value)

        search: (e) =>
          e.preventDefault()
          value = @ui.searchInput.val()
          app.router.navigate "search/#{value}?type=text", trigger: true

        onBeforeRender: =>
          unless app.request("sidebar:visible") is true
            @reset()

        onRender: =>

          # console.dir 'SidebarLayout: render'
          setTimeout =>
            @bindUIElements()
            @globalListeners()
          , 50
          @$el.removeClass("hide")
          if app.request("sidebar:visible") is false
            @slideSidebarIn()

The issue is with this line:

searchResult.on "change:params", @setSidebarContent, @

I get this error:

Uncaught TypeError: Cannot call method 'show' of undefined

I'm assuming this has something to do with the region not being defined, or a relevant context not being passed through.

So, after tons of research and about 5 hours of nonsense, I read up on the docs for listenTo and it seems this code should work:

@listenTo searchResult, "change:params", @setSidebarContent()

The only way I was actually able to get it working, however, was to do this exact code:

searchResult.listenTo @, "change:params", @setSidebarContent()

So, I have it working now, and beautifully. I'm just confused why on earth I had to pass it through this way and why that first way didn't seem to work?

Upvotes: 1

Views: 2858

Answers (1)

user2708046
user2708046

Reputation: 41

Remove the () after @setSidebarContent - this has gotten me in the past too.

@listenTo searchResult, "change:params", @setSidebarContent

Upvotes: 4

Related Questions