flashpunk
flashpunk

Reputation: 772

Backbone - loading JSON into collection won't render in the view

I can't seem to get JSON that is loading into my FriendsCollection to render into FriendListView. I can see that it is loading through the network panel, and I can log the data to the console, but for some reason the fetch command isn't passing the data to the view to be rendered.

I'm using Backbone 1.0.

The code i'm using is available on jsbin here: http://jsbin.com/OHePaki/1/edit?html,js,output

// MODELS
var ArtifactModel = Backbone.Model.extend({
    initialize: function() {
        this.on('reset', function(){ artifactView.render() })
    },
    defaults: {
        "text": "Unknown Text",
        "timestamp": "Unknown timestamp"
    }
});
var artifactModel = new ArtifactModel();

// COLLECTIONS
var ArtifactCollection = Backbone.Collection.extend({
    model: ArtifactModel,
    url: '/getDigest.json',
    // url: 'http://we365.local/Artifact/GetShareableArtifact?token=b88d2640826bb8593f6edb308ce604f28225f240&artifact_id=2&social_site=tw&log_inside=&go',
    parse: function(data) {
        console.log('running parse');
        return _.map(data.response.content, _.identity);
    },
    initialize: function(){
        this.on('reset', function(){ artifactListView.render(); }),
        console.log('running init function for ArtifactCollection');
        this.fetch();
        //this.reset(artifactjson, { parse: true });
        console.log(this.toJSON());
    }
});
var artifactCollection = new ArtifactCollection();


// VIEWS
    var ArtifactView = Backbone.View.extend({
        tagName: 'li',
        className: 'single-model',
        render: function(){
            var template = Handlebars.compile($('#stream_getDigest').html());
            this.$el.html(template(this.model.toJSON()));
            return this;
        }
    });

    var ArtifactListView = Backbone.View.extend({
        initalize: function(){
            this.collection.on('add', this.addOne, this);
        },
        render: function(){
            this.collection.forEach(this.addOne, this);
        },
        addOne: function(artifactModel){
            var artifactView = new ArtifactView({model: artifactModel});
            this.$el.append(artifactView.render().el);
        }
    });


// rendering
var artifactView = new ArtifactView({model: artifactModel});
var artifactListView = new ArtifactListView({collection: artifactCollection});

artifactView.render();
artifactListView.render();

$('#list').html(artifactListView.$el.html());

Upvotes: 1

Views: 1281

Answers (2)

BMH
BMH

Reputation: 4340

By default jQuery ajax call is asynchronous, the code will keep running without waiting for the .fetch() to be finished. In your code the view is rendered before the collection is ready so the data for the view is empty.

You can pass jQuery ajax option to fetch function so you can do the following (http://backbonejs.org/#Collection-fetch):

...
initialize: function(){
    this.on('reset', function(){ artifactListView.render(); }),
    console.log('running init function for ArtifactCollection');
    this.fetch({async:false});
    console.log(this.toJSON()); //This will log the loaded collection
}
...

Or you can change fetching strategy to take the advantage of asynchronous load:

this.fetch().done(function(){
    //Things to do after collection is loaded
});
//this's not good to use in init function

Upvotes: 2

David Knipe
David Knipe

Reputation: 3454

You need to set handlers on the models. Something like this:

friendModel.on('change', function() { friendView.render(); });
friendCollection.on('change', function() { friendListView.render(); });

Or better yet, put these lines in the constructors for friendModel and friendCollection (see http://backbonejs.org/#View-constructor ).

Upvotes: 2

Related Questions