Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

backbone.js models pointing to same instance of nested model

Using backbone.js, here is a quick test to demonstrate the problem I am facing with nested models.

Preface I have a Obj Model that contains 2 nested models, Obj1 and Obj2. The Obj model itself has a View (ObjView), and there is a View for the main page itself (BodyView).

The main page has a single button, id=add. Each time the button is clicked, a new Obj is added to the ObjCollection, and the ObjView adds a button (id=clickMe) to the page. The clickMe button is bound to a testFunc that console.logs this.model and this.model.get("obj1").

Problem From inspecting the console.logs, I see that while each Obj is a new instance, their nested Obj1 point to the same instance of an obj1! But each instance of Obj is obviously supposed to have their own instances of the nested models obj1 and obj2.

Any help appreciated.

$(document).ready(function(){

    var Obj1 = Backbone.Model.extend({
        defaults:{
            Attr1A   : false,
            Attr1B   : false
        }
    })

    var Obj2 = Backbone.Model.extend({
        defaults:{
            Attr2A   : false,
            Attr2B   : false
        }
    })

    var Obj = Backbone.Model.extend({
        defaults: {
            obj1    : new Obj1(),
            obj2    : new Obj2()
        }
    })

    var ObjCollection = Backbone.Collection.extend({
        model: Obj
    });


    var ObjView = Backbone.View.extend({

        initialize: function(){
            _.bindAll(this, 'render', 'testFunc');
            this.model.bind('change', this.render);
            this.model.view = this;

            $("body").append(this.render().el);
        },

        events: {
            "click #clickMe" : "testFunc"
        },

        render: function(){
            $(this.el).html('<input type ="button" id="clickMe" value="Click">')
            return this;
        },

        testFunc: function(){
            console.log(this.model); //returns Obj models with unique cids
            console.log(this.model.get("obj1")); //returns Obj1 models with the SAME cid!
        }
    });


    var BodyView = Backbone.View.extend({
        el: $('body'),

        events:{
            "click #add"  : "addObj"
        },

        initialize: function(){
            _.bindAll(this, 'render', 'addObj')
            this.collection = new ObjCollection();
            this.collection.bind('add', this.appendObj); 
        },

        addObj: function(){
            var myObj = new Obj();
            this.collection.add(myObj);
        },

        appendObj: function(myObj){
            var objView = new ObjView({
                model: myObj
            });
        }
    });
    var bodyView = new BodyView;

});

The html page is just the following with jQuery and backbone loaded.

<body>
    <input type ="button" id="add" value="Add">
</body>
like image 373
fortuneRice Avatar asked Jun 15 '11 18:06

fortuneRice


2 Answers

fortuneRice, when a Backbone model gets initialized, the super.constructor moves the defaults to the internal attributes array, where model.get looks for "obj1". Prusse's example initializes the obj1 and obj2 values with new objects for each instance, but doesn't move the values to the internal attributes array. Here is my modification of Prusse's solution.

var Obj = Backbone.Model.extend({
    initialize: function() {
        myDefaults = {
            obj1: new Obj1();
            obj2: new Obj2();
        }
        this.set(myDefaults);
});

jQuery's extend method would combine the two objects. You could declare the non-object references with defaults and the object references with myDefaults in the initialize method.

like image 166
c3rin Avatar answered Oct 14 '22 12:10

c3rin


With:

var Obj = Backbone.Model.extend({
    defaults: {
        obj1    : new Obj1(),
        obj2    : new Obj2()
    }
})

You are saying that you want all objects created with "Obj" to have the same "obj1" and "obj2" values, use:

var Obj = Backbone.Model.extend({
    initialize: function() {
        this.obj1 = new Obj1();
        this.obj2 = new Obj2();
    }
});

To achieve what you seen to want. http://documentcloud.github.com/backbone/#Model-constructor

like image 36
Prusse Avatar answered Oct 14 '22 13:10

Prusse