Search code examples
javascriptdjangobackbone.jsunderscore.jstastypie

cannot populate backbone collection from backbone.js tutorial


I am working my way through the backbone tutorial here: http://backbonetutorials.com/

I am using django + tastypie for the restful api and backbone + underscore as the tutorial suggests for the frontend.

However, I am unable to loop through the collection of users that I fetch.

Here is my code (in a django template):

{% extends "my_app/base_template.html" %}

{% block scripts %}

  <script type="text/template" id="users_template">
    <table class="table striped">
      <thead>
        <tr>
          <th>username</th>
        </tr>
      </thead>
      <tbody>
        <% _.each(users, function(user) { %>
          <tr>
            <td><%= user.get('username') %></td>
          </tr>
        <% }); %>
      </tbody>
    </table>
  </script>

  <script type="application/javascript">
    $(document).ready(
      function() {

        var Users = Backbone.Collection.extend({
          url : "/api/q/user/"
        });

        var UserList = Backbone.View.extend({
          el : ".user_list",
          render : function() {
            var that = this;
            var users = new Users();
            users.fetch({
              success : function(users) {
                var template = _.template($("#users_template").html());
                {# I think that the problem is around here #}
                that.$el.html(template({users : users.models}));
              }
            });
          }
        });

        var user_list = new UserList();

        var Router = Backbone.Router.extend({
          routes : {
            "" : "index"
          }
        });

        var router = new Router();

        router.on("route:index", function(){
          user_list.render();
        });

        Backbone.history.start();

      }
    );
  </script>

{% endblock %} {# /scripts #}

{% block content %}

  <div class="my_stuff">
    <div class="user_list"/>
  </div>

{% endblock %} {# /content #}

And I can confirm that going to "my_domain/api/q/user/" returns the correct content (2 users: the admin and another user "bob"):

{
  "meta": {
  "limit": 20, 
  "next": null, 
  "offset": 0, 
  "previous": null, 
  "total_count": 2
}, 
"objects": [
  {
    "date_joined": "2014-11-04T04:28:17", 
    "email": "[email protected]", 
    "first_name": "Bob", 
    "id": 2, 
    "is_active": true, 
    "is_staff": false, 
    "is_superuser": false, 
    "last_login": "2014-11-04T05:13:46.908539", 
    "last_name": "Bobbington", 
    "password" : "some hash",
    "resource_uri": "/api/q/user/2/", 
    "username": "bob"
  }, 
  {
    "date_joined": "2014-11-03T13:44:04.356967", 
    "email": "[email protected]", 
    "first_name": "", 
    "id": 1, 
    "is_active": true, 
    "is_staff": true, 
    "is_superuser": true, 
    "last_login": "2014-11-04T06:06:51.336317", 
    "last_name": "", 
    "password": "some_hash", 
    "resource_uri": "/api/q/user/1/", 
    "username": "admin"
  }] 
}

So, what am I doing wrong? Should I be passing something other than {{{users.models}} to the template? Am I looping through that stucture incorrectly?

Thanks.


Solution

  • Out-of-the box, Backbone expects your objects to be at the root of your response. If they're not, it needs some help to determine what part of the response it can use when instantiating model objects.

    Basically you just need to define a Backbone model and add your own parse function:

    var user = Backbone.Model.extend({
        parse: function(response) {
            return response.objects;
        }
    });
    

    Now your model will know where it can find the properties you want to set.