Search code examples
ruby-on-railsbackbone.jscoffeescriptbackgrid

Where do I initialize backgrid in my Backbone/Rails app?


I have a Backbone.js app and am trying to integrate with Backgrid, but I am having trouble understanding where I should be calling new Backgrid. I tried calling it in my view after things get rendered but appending the grid doesn't work because things aren't actually rendered yet. Here is some code:

SpreadsheetIndex.js.coffee

D3.Views.SpreadsheetsIndex = Support.CompositeView.extend
  initialize: (options) ->
    this.tables = options.tables
    this.resources = options.resources
    _.bindAll(this, 'render')

  render: ->
    this.renderTemplate()
    this.renderSpreadsheets()

    resources = this.resources

    this.tables.each (table) ->

      subset = resources.subcollection
        filter: (resource) -> 
          resource.escape('table_id') == table.escape('id')

      grid = new Backgrid.Grid
        columns: table.attributes.columns
        collection: subset

      $("#"+table.escape('id')).append(grid.render().$el);
    return this

  renderTemplate: ->
    this.$el.html(JST['spreadsheets/index']({ spreadsheets: this.tables }))

  renderSpreadsheets: ->
    self = this
    self.$('tbody').empty();

spreadsheets/index.jst.ejs

<% spreadsheets.each(function(spreadsheet) { %>
  <h4><%= spreadsheet.escape('name')%></h4>
  <div id='<%= spreadsheet.escape('id') %>'></div>
<% }) %>

The issue is that the $("#"+table.escape('id')) selector does not select anything because the template hasn't rendered yet. It feels like I'm putting this in the wrong place. What am I doing wrong?


Solution

  • I'd guess that you want to use the view's @$ method to instead of $ to localize the selector to the view's el:

    this.tables.each (table) =>
      #...
      @$("#"+table.escape('id')).append(grid.render().$el);
    

    Note that -> has become => (to get the right @/this) and it now uses @$ instead of $.


    While I'm here, you can do a couple other things to make your code more ideomatic:

    1. Say class D3.Views.SpreadsheetsIndex extends Support.CompositeView instead of the JavaScripty D3.Views.SpreadsheetsIndex = Support.CompositeView.extend.
    2. Use @ instead of this, for example @tables = options.table rather than this.tables = options.table.
    3. You can use string interpolation instead of + if you think it is cleaner:

      @$("##{table.escape('id')}")
      
    4. You rarely need bindAll, instead of _.bindAll(this, 'render') you could define render as render: => to get the binding to happen automatically.

    5. You rarely need the var self = this trick in CoffeeScript, you can usually use a => instead. And you don't need either one here:

      renderSpreadsheets: ->
        self = this
        self.$('tbody').empty();
      

      you can just renderSpreadsheets: -> @$('tbody').empty()