10
votes

I need to render a model's attributes to JSON so I can pass them into a template. Here is what a render() function for a view looks like:

render: function() {
  console.log(this.model);
  console.log(this.model.toJSON());
  $(this.el).html(this.template(this.model.toJSON()));
  return this;
},

Here is the attributes output after doing console.log(this.model):

created_at: "2012-04-19"
id: "29"
name: "item"
resource_uri: "/api/v1/item/29/"
updated_at: "2012-04-21"
user: "/api/v1/user/9/"

Here is the model's JSON output after doing console.log(this.model.toJSON()):

id: "29"
__proto__: Object

What happened?

Edit: Here is the instantiation:

  var goal = new Goal({id: id});
  goal.fetch();
  var goalFullView = new GoalFullView({
    model: goal,
  });

Here are the contents of the new view:

  console.log(this.model.attributes);
  console.log(this.model.toJSON());

Here is what the console says:

Object
created_at: "2012-04-23"
id: "32"
name: "test"
resource_uri: "/api/v1/goal/32/"
updated_at: "2012-04-23"
user: "/api/v1/user/9/"
__proto__: Object

Object
id: "32"
name: "test"
__proto__: Object

If the toJSON is supposed to make a clone of the attributes, why doesn't it copy the correct name or why doesn't it copy the created_at, updated_at fields?

Edit 2: Here is the model:

  var Goal = Backbone.Model.extend({

    // Default attributes for Goal
    defaults: {
      name: "empty goal",
    },

    // Check that the user entered a goal
    validate: function(attrs) {
      if (!attrs.name) {
        return "name is blank";
      }
    },

    // Do HTTP requests on this endpoint
    url: function() {
      if (this.isNew()) {
        return API_URL + "goal/" + this.get("id") + FORMAT_JSON;
      }
      return API_URL + "goal/" + FORMAT_JSON;
      //API_URL + "goal" + FORMAT_JSON, 
    },
  });

Edit 3: I figured out that I need to use the success callback from fetch to render a view that uses the model:

goal.fetch({success: function(model) { var goalFullView = new GoalFullView({ model: goal, }); }});

1
can you show the model and its instantiation as well?mindandmedia
You have something else in your code that makes the other attributes invisible for toJSON(), perhaps look at your Model or paste, how you are initializing it ... see jsfiddledrinchev
I edited the original post with the Model class. I cannot seem to figure out why the toJSON does not work. Even though, this.model.attributes prints out the correct list of attributes, when I try to do this.model.get("id") or any of the other attributes, they come up as empty. Clearly, it is present when I call attributes on the model instance, though.egidra

1 Answers

27
votes

The toJSON() method just returns a shallow clone of the model's attributes property.

From the annotated Backbone.js source:

toJSON: function(options) {
  return _.clone(this.attributes);
}

Without seeing more of your code, it looks like you directly set properties on the model object, rather than using the set function to set model attributes.

I.e. don't do this:

model.name = "item";

do this:

model.set("name", "item");

EDIT:

For your specific issue, it's possible that you called toJSON before the model had finished loading from the server.

E.g. This won't always work as expected:

var model = new Goal({id: 123});
model.fetch();
console.log(model.toJSON());

But this will:

var model = new Goal({id: 123});
model.fetch({
  success: function() {
    console.log(model.toJSON());
  }
});