0
votes

I'm having issues syncing JSON data received from the server with my views after a fetch.

I do not have a collection of "mainmodel", because I'm only working with one "mainmodel" at a time but numerous "mymodel", anyhow, the structure follows:

    var mymodel = Backbone.Model.extend({
        defaults: {k1:"",
                   k2:"",
                   k3:""}
    });

    var collection = Backbone.Collection.extend({model:mymodel,});

    var mainmodel = Backbone.Model.extend({
        defaults: {v1:"",
                   v2:"",
                   v3:"",
                   v4:new collection()
    });

I create the nested views for "mymodel" from a render function in a parent view. This works..., only when I'm working with a new model.

// My ParentView render function
render: function() {
for (var i = 0; i < this.model.v4.length;i++) {
    var view = new MyModelView({model:this.model.v4.at(i)});
    this.$el.append($(view.render().el));
}
this.$el.append(this.template(this.model.toJSON()));
return this;
},

// The MyModelView render function below 
render: function() {
    this.$el.html(this.template(this.model.toJSON()));
return this;
},

Now, the above works if I open my application and create models from there. However, If I open my app and supply an id, I make a fetch to the server, retrieve the data, and create a new ParentView I end up getting an error that says "this.model.v4.at not a function". Ugh.

So now, if I change the FIRST render function to be, changing the at(i) to [i]

    var view = new MyModelView({model:this.model.v4[i]});

And change the second render function, removing toJSON, to be:

    this.$el.html(this.template(this.model)); 

It renders. But I still can't move around views without errors. No surprise. I have used console.log(JSON.stringify(this.model)); as they arrive into the parentView and MyModelView. The JSON returned looks like this, whether fetched or created.

    {"v1":"val1",
     "v2":"val2,
     "v3":"val3",
     "v4":[{"k1":"key1","k2":"key2","k3","key"}, { ... }, { ... }]
    }

The JSON data structures appear to be identical. I thought the JSON format was incorrect, so I tried using JSON.parse before handing the model to the view, but that didn't work. Maybe I'm way off, but I originally thought I had a JSON formatting issue, but now I don't know. The server is returning content as 'application/json'.

Edit: The JSON values for v1,v2,v3 render correctly.

Any ideas?

1

1 Answers

3
votes

You have two problems: one you know about and one you don't.

The problem you know about is that your mainmodel won't automatically convert your v4 JSON to a collection so you end up with an array where you're expecting a collection. You can fix this by adding a parse to your mainmodel:

parse: function(response) {
    if(response.v4)
        response.v4 = new collection(response.v4);
    return response;
}

The problem you don't know about is that your defaults in mainmodel has a hidden reference sharing problem:

var mainmodel = Backbone.Model.extend({
    defaults: {
        //...
        v4: new collection()
    }
});

Anything you define in the Backbone.Model.extend object ends up on your model's prototype so the entire defaults object is shared by all instances of your model. Also, Backbone will do a shallow copy of defaults into your new models. So if you m1 = new mainmodel() and m2 = new mainmodel(), then m1 and m2 will have exactly the same v4 attribute. You can solve this by using a function for defaults:

var mainmodel = Backbone.Model.extend({
    defaults: function() {
        return {
            v1: '',
            v2: '',
            v3: '',
            v4: new collection()
        };
    }
});