Question

I am a complete n00b to Backbone.js, and have only been working with it for a few days. I am attempting to fetch JSON data to populate the model, and in this scenario I have two models that I need to generate. Here is the sample JSON I have been working with:

JSON

{
"status": "200",
"total": "2",
    "items":
    [{
        "id": "1",
        "name": "Here is another name",
        "label": "Label for test",
        "description": "A description for more information.",
        "dataAdded": "123456789",
        "lastModified": "987654321"
    },
    {
        "id": "2",
        "name": "Name of item",
        "label": "Test Label",
        "description": "This is just a long description.",
        "dataAdded": "147258369",
        "lastModified": "963852741"
    }]
}

Backbone JS

// MODEL
var Service = Backbone.Model.extend({
defaults: {
    id: '',
    name: '',
    label: '',
    description: '',
    dateAdded: '',
    dateModified: ''
}
});
var service = new Service();

// COLLECTION
var ServiceList = Backbone.Collection.extend({
    model: Service,
    url: "./api/service.php",
    parse: function(response) {
        return response.items;
    }
});
//
var serviceList = new ServiceList();
var jqXHR = serviceList.fetch({
    success: function() {
        console.log("Working!");
                console.log(serviceList.length);
    },
    error: function() {
        console.log("Failed to fetch!");
    }
});


// VIEW for each Model
var ServiceView = Backbone.View.extend({
    el: $('.widget-content'),
    tagName: 'div',
    template: _.template($('#service-template').html()),
    initialize: function() {
        this.collection.bind("reset", this.render, this);
    },
    render: function() {
        console.log(this.collection);
        this.$el.html('');
        var self = this;
        this.collection.each(function(model) {
            self.$el.append(self.template(model.toJSON()));
        });
        return this;
    }
});
//
var serviceView = new ServiceView({
    collection: serviceList
});
console.log(serviceView.render().el);

html

<div class="widget-content">
    <!-- Template -->
    <script type="text/template" id="service-template">
        <div><%= name %></div>
    </script>
</div>

When I console log the serviceList.length I get the value 2, so I believe the JSON object is fetched successfully. I also get the "Working!" response for success too. However, in the view I am showing an empty object, which gives me an empty model.

I am still trying to understand the best way to do this too. Maybe I should be using collections for the "items" and then mapping over the collection for each model data? What am I doing wrong? Any advice or help is greatly appreciated.

No correct solution

OTHER TIPS

I can see two problems. First, you want to remove serviceList.reset(list). Your collection should be populated automatically by the call to fetch. (In any case the return value of fetch is not the data result from the server, it is the "jqXHR" object).

var serviceList = new ServiceList();
var jqXHR = serviceList.fetch({
    success: function(collection, response) {
        console.log("Working!");

        // this is the asynchronous callback, where "serviceList" should have data
        console.log(serviceList.length);
        console.log("Collection populated: " + JSON.stringify(collection.toJSON()));
    },
    error: function() {
        console.log("Failed to fetch!");
    }
});
// here, "serviceList" will not be populated yet

Second, you probably want to pass the serviceList instance into the view as its "collection". As it is, you're passing an empty model instance into the view.

var serviceView = new ServiceView({
    collection: serviceList
});

And for the view, render using the collection:

var ServiceView = Backbone.View.extend({
    // ...

    initialize: function() {
        // render when the collection is reset
        this.collection.bind("reset", this.render, this);
    },
    render: function() {
        console.log("Collection rendering: " + JSON.stringify(this.collection.toJSON()));

        // start by clearing the view
        this.$el.html('');            

        // loop through the collection and render each model
        var self = this;
        this.collection.each(function(model) {
            self.$el.append(self.template(model.toJSON()));
        });
        return this;
    }
});

Here's a Fiddle demo.

The call serviceList.fetch is made asynchronously, so when you try console.log(serviceList.length); the server has not yet send it's response that's why you get the the value 1, try this :

var list = serviceList.fetch({
    success: function() {
        console.log(serviceList.length);
        console.log("Working!");
    },
    error: function() {
        console.log("Failed to fetch!");
    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top