3
votes

I'm new to Backbone, and I'm very confused about what's happening when I pass a JSON array (of objects) to a Backbone Collection.

I'm fetching some JSON from a spreadsheet hosted on Google Drive. I'm parsing that data, as the actual data that I want to use in my collection is deeply nested. In my parse function, if I log the length of my desired array, I get 157 (that's correct). I then pass that array into a Backbone Collection, and the length of my collection is 1 (incorrect). It's as though foo.bar.length = 157, but there is only one 'bar' in 'foo', so when I pass foo.bar into the collection, it takes foo.bar and not the contents of foo.bar! Very confused.

Code below...

var table = new TableView();

TableItem = Backbone.Model.extend(),

TableItemCollection = Backbone.Collection.extend( {
    model : TableItem,
    url : 'https://spreadsheets.google.com/feeds/list/0AjbU8ta9j916dFdjSVg3YkNPUUJnWkZSWjBDWmZab3c/1/public/basic?alt=json-in-script',
    sync : function( method, model, options ) {
        var params = _.extend( {
            type: 'GET',
            dataType: 'jsonp',
            url: this.url,
            processData: false
        }, options );
        return $.ajax( params );
    },
    parse : function( resp, xhr ) {
        console.log( resp.feed.entry.length ); // THIS LOGS 157
        return resp.feed.entry;
    }
} ),

TableView = Backbone.View.extend( {
    initialize  : function ( options ) {
        this.collection = new TableItemCollection();
        this.collection.on( 'reset', this.parseResponse, this );
        this.collection.fetch( {
            reset : true,
            success : function ( model, response, options ) {
                console.log( 'OK' );  // THIS LOGS 'OK'
            },
            error : function ( model, response, options ) {
                console.log( 'ERROR' );
            }
        } );
    },
    parseResponse : function () {
        console.log( this.collection.length ); // THIS LOGS 1
    }
} );
1
What is the type of the resp.feed.entry are you sure that it is an array? Please log out in your parse method console.log(_.isArray(resp.feed.entry))!nemesv

1 Answers

3
votes

If you dump one of the items returned by Google Spreadsheets, you will see that the data is nested in multiple objects, something like this

{
    "id":{"$t":"https://spreadsheets.google.com/feeds/list/..."},
    "updated":{"$t":"2013-07-30T12:01:24.000Z"},
    "category":[{"scheme":"...","term":"..."}],
    "title":{"type":"text","$t":"ACIW"},
    "content":{},
    "link":[{"rel":"self","type":"application/atom+xml","href":"..."}]
}

In a Fiddle http://jsfiddle.net/nikoshr/kHBvY/

Note how the id property is wrapped in an object "id":{"$t":"https://spreadsheets.google.com/feeds/list/0AjbU8ta9j916dFdjSVg3YkNPUUJnWkZSWjBDWmZab3c/1/public/basic/cokwr"}

Backbone collections don't allow duplicates and duplicates are determined based on their id. All your items are considered duplicates and collapsed into one. If you remove the id or disambiguate it, you will get your 157 items. For example,

parse : function( resp, xhr ) {
    var data = resp.feed.entry, i;
    console.log(data.length); // THIS LOGS 157

    for (i=data.length-1; i>=0; i--)
        data[i].id  = data[i].id['$t'];

    return data;
}

http://jsfiddle.net/nikoshr/kHBvY/2/ for a demo

You probably will have to unwrap all the attributes to use them in a non hair pulling way.