Backbone.js: Fetch a collection of models and render them

19,033

Solution 1

There are 2 potential problems with your code.

  1. The event listener callback should be registered before calling the collection.fetch(). Otherwise, you might miss the first reset event as it might be triggered before the listener is registered.

  2. The reset event is not enough to ensure that the view will re-render every time the collection gets updated.

Also, note that it is a good practice to use the object.listenTo() form to bind events as it will ensure proper unregistration when the view is closed. Otherwise, you may end up with what is known as Backbone zombies. Here is a solution.

this.listenTo( this.collection, 'reset add change remove', this.render, this );
this.collection.fetch({ data: { fetch:true, type:"post", page:1 } });

Note how you can register multiple events from the same object by separating them with whitespace.

Solution 2

change

this.collection.bind('reset', this.render, this);

to

this.collection.bind('sync', this.render, this);

The problem is you perform reset only once, in the beginning. And at that time you don't have anything to render. The next time, when you fetch your collection, reset event doesn't fire, because you fetch collection without option {reset: true}.

Solution 3

Change this line

this.collection.bind('reset', this.render, this);

to

this.listenTo(this.collection, 'reset', this.render);
Share:
19,033
hyde
Author by

hyde

Dust

Updated on June 13, 2022

Comments

  • hyde
    hyde almost 2 years

    I am learning JavaScript MVC application development using Backbone.js, and having issues rendering model collection in the view. Here's what I want to do:

    • After the page finishes loading, retrieves data from the server as model collection

    • Render them in the view

    That's all I want to do and here is what I have so far:

    $(function(){
    
        "use strict";
    
        var PostModel = Backbone.Model.extend({});
    
        var PostCollection = Backbone.Collection.extend({
            model: PostModel,
            url: 'post_action.php'
        });
    
        var PostView = Backbone.View.extend({
            el: "#posts-editor",        
    
            initialize: function(){
                this.template = _.template($("#ptpl").html());
                this.collection.fetch({data:{fetch:true, type:"post", page:1}});
                this.collection.bind('reset', this.render, this);
            },
    
            render: function(){
                var renderedContent = this.collection.toJSON();
                console.log(renderedContent);
                $(this.el).html(renderedContent);
                return this;
            }
        });
    
        var postList = new PostCollection();
        postList.reset();
        var postView = new PostView({
            collection: postList
        });
    
    });
    

    Problem

    As far as I know, Chrome is logging the response from the server and it's in JSON format like I want it. But it does not render in my view. There are no apparent errors in the console.

    The server has a handler that accepts GET parameters and echos some JSON: http://localhost/blog/post_action.php?fetch=true&type=post&page=1

    [
       {
          "username":"admin",
          "id":"2",
          "title":"Second",
          "commentable":"0",
          "body":"This is the second post."
       },
       {
          "username":"admin",
          "id":"1",
          "title":"Welcome!",
          "commentable":"1",
          "body":"Hello there! welcome to my blog."
       }
    ]
    
  • hyde
    hyde almost 11 years
    I did that but now I get Uncaught Error: A "url" property or function must be specified in the console but I have the url property set to post_action.php.
  • Artem Volkhin
    Artem Volkhin almost 11 years
    I have no idea how it can become broken with this change. Maybe you should try remove "use strict"; for now? Looks like it's something inside library. Just try to add urlRoot: 'post_action.php' to your model.
  • Artem Volkhin
    Artem Volkhin almost 11 years
    No, he will not receive reset event after fetching. Btw, the only difference in your solution is context and unbinding. Why do you think it should help?
  • Jason Kim
    Jason Kim almost 10 years
    Only solution on this topic that worked! Thanks @mor
  • Pea
    Pea almost 9 years
    Can you explain what you mean by the onFetch callback which needs to "be registered before calling the collection.fetch(). Otherwise, you might miss the first reset event"? That is, I don't see an onFetch callback function in the original code or your example.
  • mor
    mor almost 9 years
    @Pea you are right, this is confusing. I am referring to the event listener. I will edit.
  • Pea
    Pea almost 9 years
    @mor Thanks for taking the time to explain and update. It's very helpful.
  • alexserver
    alexserver over 8 years
    which version are you using ? I'm using 0.9.2 and having an error on listenTo.