Reputation: 1145
I'm working on a project where the request and response payloads are all namespaced. For example:
{
'SourceMachine':{
'Host':'some value',
'Description':'some value',
'UserName':'some value',
'Password':'some value'
}
}
To be able to do get() and set() on the individual fields, I overrode the parse method in my "source_model" like so:
parse : function(response, xhr) {
return response.SourceMachine;
}
That's all well and good. But the issue is this: When I want to do a POST or PUT operation, I have to get the Host, Description, UserName and Password attributes into the SourceMachine namespace. Basically what I've been doing is copying the model attributes to a temporary object, clearing out the model, then saving as follows:
var tempAttributes = this.model.attributes;
this.model.clear();
this.model.save({SourceMachine: tempAttributes});
This works, but it screams of KLUGE! There's got to be a better way of working with namespaced data. Thanks!
Update
I've now created a require.js module for a base model that I'll be using for all the models in my app, since they all rely on namespaced data:
define(function() {
return Backbone.Model.extend({
/**
* Adding namespace checking at the constructor level as opposed to
* initialize so that subclasses needn't invoke the upstream initialize.
* @param attributes
* @param options
*/
constructor : function(attributes, options) {
//Need to account for when a model is instantiated with
//no attributes. In this case, we have to take namespace from
//attributes.
this._namespace = options.namespace || attributes.namespace;
//invoke the default constructor so the model goes through
//its normal Backbone setup and initialize() is invoked as normal.
Backbone.Model.apply(this, arguments);
},
/**
* This parse override checks to see if a namespace was provided, and if so,
* it will strip it out and return response[this._namespace
* @param response
* @param xhr
* @return {*}
*/
parse : function(response, xhr) {
//If a namespace is defined you have to make sure that
//it exists in the response; otherwise, an error will be
//thrown.
return (this._namespace && response[this._namespace]) ? response[this._namespace]
: response;
},
/**
* In overriding toJSON, we check to see if a namespace was defined. If so,
* then create a namespace node and assign the attributes to it. Otherwise,
* just call the "super" toJSON.
* @return {Object}
*/
toJSON : function() {
var respObj = {};
var attr = Backbone.Model.prototype.toJSON.apply(this);
if (this._namespace) {
respObj[this._namespace] = attr;
} else {
respObj = attr;
}
return respObj;
}
})
});
Upvotes: 2
Views: 418
Reputation: 434785
Create and update operations on models call toJSON
to produce the data for the server:
toJSON
model.toJSON()
Return a copy of the model's attributes for JSON stringification. This can be used for persistence, serialization, or for augmentation before being handed off to a view.
You could provide your own toJSON
:
toJSON: function() {
return { SourceMachine: _(this.attributes).clone() };
}
That should make your server happy. Unfortunately, toJSON
is also commonly used to provide data for your templates and you probably don't want the SourceMachine
noise in there; if so, then add another method to prepare data for your templates:
// Or whatever you want to call it...
valuesForTemplate: function() {
return _(this.attributes).clone();
}
That's what the standard toJSON
method does internally.
Upvotes: 2