changelog
changelog

Reputation: 4681

Event binding with views and AJAX-loaded collections

I'm starting out with Backbone.JS, and have a question about how this should work.

I have a page which should load a list of sports, and then render the view. Now, because the list of sports is loaded via AJAX, I need to bind events to the collection so that it's only rendered when the data from that collection is actually loaded.

Here's what I've got so far:

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">

    <title>Test</title>
    <script src="../../src/vendor/zepto.js" type="text/javascript" charset="utf-8"></script>
    <script src="../../src/vendor/underscore.js" type="text/javascript" charset="utf-8"></script>
    <script src="../../src/vendor/backbone.js" type="text/javascript" charset="utf-8"></script>
  </head>
  <body>
    <div id="sportsList"></div>

    <script type="text/template" id="sports-template">
      <ul>
        <% _.each(sports, function(sport){ %>
        <li>
          <%= sport.getDescription() %>
        </li>
        <% }); %>
      </ul>
    </script>

    <script type="text/javascript" charset="utf-8" src="application.js"></script>
  </body>
</html>

As for the javascript code:

var Sport = Backbone.Model.extend({

  getDescription: function() {
    return this.get('description');
  }
});

var Sports = Backbone.Collection.extend({
  model: Sport,
  initialize: function(options) {
    this.bind("refresh", function() {
      options.view.render();
    });

    var sports = this;
    $.ajax({
      url: 'http://localhost:8080/?service=ListSportsService&callback=?',
      dataType: 'jsonp',
      success: function(data) {
        sports.refresh(data);
      }
    });
  }
});

var SportsView = Backbone.View.extend({
  el: '#sportsList',
  template: _.template($('#sports-template').html()),
  initialize: function() {
    this.model = new Sports({view: this});
  },
  render: function() {
    $(this.el).html(this.template({sports: this.model.models}));
    return this;
  }
});

var SportsController = Backbone.Controller.extend({
  routes: {
    'sports': 'listSports'
  },

  listSports: function() {
    new SportsView();
  }
});

$(document).ready(function(){
  window.app = new SportsController();
  Backbone.history.start();
});

The part that really nags me is having to pass the view to the collection and binding the refresh event there so that I can render the view once everything is loaded.

My question is, is there a DRYer/simpler way of doing this that I'm missing?

Keep in mind I'm using ZeptoJS instead of jQuery.

Upvotes: 2

Views: 3545

Answers (1)

Julien
Julien

Reputation: 9216

Your collection should read

var Sports = Backbone.Collection.extend({
  model: Sport,
  url: '/?service=ListSportsService&callback=?'
});

Always use Backbone.sync functionality when possible (here by specifying the url on the collection and using fetch).

Your controller should read

var SportsController = Backbone.Controller.extend({
  routes: {
    'sports': 'listSports'
  },

  listSports: function() {
    //create the view with the collection as a model
    this.sports = new Sports();
    this.view = new SportsView({model: this.sports});
    this.sports.bind("refresh", this.view.render);

    // fetch all the sports
    this.sports.fetch();
  }
});

Enjoy.

Upvotes: 4

Related Questions