bala
bala

Reputation: 436

Getting a json from collection to view in backbone.js

I am new to backbone.js and is having some problem with my app. I have a collection which relies on a json data source. I am able to console.log the json in my parse method. Is that enough to bind the collection to my view? I don't understand the use of fetch method.

My collection looks like as follows,

(function (collections,model) {
collections.Directory = Backbone.Collection.extend({
        initialize : function(){
            console.log('we are here');
            },
        model:model.item,
        url:'collections/json/data.json',
        parse:function(response){
                console.log(response);
                return response;
            }
    });
})(app.collections,app.models);

And my master view looks like this,

(function(views,collections){

views.masterView = Backbone.View.extend({
         el : $("#contacts"),
        initialize : function(){
            console.log('view initialize inside render');
            this.render();
            this.$el.find("#filter").append(this.createSelect());
            this.on("change:filterType", this.filterByType, this);
            this.collection.on("reset", this.render, this);
            this.collection.on("add", this.renderContact, this);
            //console.log('we are here'+app.collections.CollectionItems.fetch());
            console.log('view initialize');
        },

        render : function(){

            this.$el.find("article").remove();
            _.each(this.collection.models,function(item){

                this.renderContact(item);
               },this);

            },
             renderContact: function (item) {
            views.contactView = new app.views.ContactView({
                model: item
            });
            this.$el.append(contactView.render().el);
        },
            getTypes : function () {
            return _.uniq(this.collection.pluck("Qno"));
        },
    createSelect : function () {

        var select = $("<select/>", {
                    html: "<option value='all'>All</option>"
                });
    _.each(this.getTypes(), function (item) {
        var option = $("<option/>", {
            value: item.toLowerCase(),
            text: item.toLowerCase()
        }).appendTo(select);
    });
    return select;
    },
     events: {
            "change #filter select": "setFilter",
            "click #add": "addContact",
            "click #showForm": "showForm"
        },
    setFilter : function(e){
        this.filterType = e.currentTarget.value;
        this.trigger("change:filterType");

    },
    filterByType: function () {
    if (this.filterType === "all") {
        this.collection.reset(contacts);
        routerURL.navigate("filter/all");
    } else {
        this.collection.reset(contacts, { silent: true });
        var filterType = this.filterType,
            filtered = _.filter(this.collection.models, function (item) {
            return item.get("type").toLowerCase() === filterType;
        });
        this.collection.reset(filtered);
        routerURL.navigate("filter/"+filterType);
    }
},
    addContact : function(e){
        e.preventDefault();
        var contModel = {};
        $("#addContact").children("input").each(function(i, el){
            if($(el).val() !== "")
                contModel[el.id] = $(el).val();

        });
        contacts.push(contModel);
        if (_.indexOf(this.getTypes(), contModel.type) === -1) {
                this.collection.add(new Contact(contModel));
                this.$el.find("#filter").find("select").remove().end().append(this.createSelect());
            } else {
                this.collection.add(new Contact(contModel));
            }
    },
    showForm : function(){
        this.$el.find("#addContact").slideToggle();   
    }

        });
      })(app.views,app.collections);

my model is very simple and looks like this,

(function ( models ) {
    models.Item = Backbone.Model.extend({
        defaults :{Qno:'1',Desc:'hello'}
        });
})( app.models );

ihave one js file instantiatin viewsand collections

    (function () {

        window.app = {};
        app.collections = {};
        app.models = {};
        app.views = {};
        app.mixins = {};

       $(function(){
                app.collections.CollectionItems = new app.collections.Directory();
                //app.collections.CollectionItems.fetch();
                //console.log(app.collections.CollectionItems.fetch());

                app.collections.CollectionItems.fetch({
                    success: function (collection,response) {
                        console.log(response);
                    }
                });
                //console.log(app.collections.CollectionItems.toJSON());
                console.log('coll started');
                app.views.app = new app.views.masterView({collection: app.collections.CollectionItems});
                console.log('view is jus about fine!!');
                //app.views.pagination = new app.views.PaginatedView({collection:app.collections.paginatedItems});
        });






    var ContactsRouter = Backbone.Router.extend({
    routes: {
        "filter/:type": "urlFilter"
    },
    urlFilter: function (type) {
        master.filterType = type;
        master.trigger("change:filterType");
    }
});

    var routerURL = new ContactsRouter();

    Backbone.history.start();
})();

my landing page looks like this with a template in it

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <title>Backbone.js Web App</title>
        <link rel="stylesheet" href="css/screen.css" />
    </head>
    <body>

        <div id="contacts">

</div>

        <script id="contactTemplate" type="text/template">

            <h1><%= Qno %></h1>

        </script>
        <script src="js/jquery.js"></script>
        <script src="js/underscore-min.js"></script>
        <script src="js/backbone-min.js"></script>
        <script src="app.js"></script>
        <script src="collections/Directory.js"></script>
        <script src="models/item.js"></script>
        <script src="views/masterView.js"></script>
         <script src="views/simpleView.js"></script>
        <!--<script src="js/backbone.paginator.js"></script>-->
    </body>
</html>

I just can't get my head around this. The view is not rendered with the collection data. Please help!

Upvotes: 1

Views: 899

Answers (1)

net.uk.sweet
net.uk.sweet

Reputation: 12431

I think it's because the fetch method on your collection is executed asynchronously and has therefore not completed when you create your view (if you look at the console I would expect the log statement in the success callback to display after the log statements underneath). This means that your view render method is called before the collection is populated and the reset event (which you're binding to in your view) is never triggered.

Try updating the code which instantiates everything as follows:

   $(function(){
            app.collections.CollectionItems = new app.collections.Directory();
            //app.collections.CollectionItems.fetch();
            //console.log(app.collections.CollectionItems.fetch());

            app.collections.CollectionItems.fetch({
                success: function (collection,response) {
                    console.log(response);
                    app.views.app = new app.views.masterView({collection: app.collections.CollectionItems});
                }
            });
    });

Upvotes: 1

Related Questions