Search code examples
jsontemplatesbackbone.jsrendergetter

Render view with overwritten getters in Backbone


I am building a small Backbone.js application and added some custom getters to one of the models (the name getter returns a concatenated first- and last name for example):

PersonModel = Backbone.Model.extend({
  get: function (attr) {
    if (typeof this[attr] == 'function') {
      return this[attr]();
    }
    return Backbone.Model.prototype.get.call(this, attr);
  },

  name: function() {
    return firstName + " " + lastName;
  }
})

I can now use person.get("name") to retrieve the name, nice. However, when I call toJSON on the the model these values aren't included (and I suppose that makes sense). Problem is I use this to render my views:

this.template({people: this.collection.toJSON()});

What's the best way to do this in Backbone.js? Manually creating the JSON with the overwritten getters?

Thanks!


Solution

  • You could provide your own toJSON method on PersonModel:

    toJSON: function() {
        var attr = Backbone.Model.prototype.toJSON.call(this);
        attr.name = this.name();
        return attr;
    }
    

    The collection toJSON just calls toJSON on each model:

    // The JSON representation of a Collection is an array of the
    // models' attributes.
    toJSON : function() {
      return this.map(function(model){ return model.toJSON(); });
    },
    

    so adding your own toJSON to your model should work.

    You could also add name as a real attribute and then adjust your model's validate method to update name if firstName or lastName changes and to ignore any direct attempts to change name or complain about "an attempt to edit a read-only attribute" when someone tries to pass a name change to set. There's nothing that says that validate can't change the attribute object that it is given so you could be given {firstName: 'x'} and change it to {firstName: 'x', name: 'x ' + this.get('lastName')} before validate returns. This would be a bit of an abuse of validate but there is no explicit prohibition against validate altering the attribute set and it is the only hook you have. I suppose you could have the model listen to change events on its own firstName and lastName and then trigger a set({name: ...}) but then you could have event ordering problems if someone else is watching only the first and last names.