Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added convenient nested get and set methods for Associated Model
  • Loading branch information
jdkanani committed Jan 4, 2013
1 parent ab327ac commit c48c2d1
Showing 1 changed file with 41 additions and 18 deletions.
59 changes: 41 additions & 18 deletions backbone-associations.js
Expand Up @@ -31,7 +31,7 @@

// Built-in Backbone `events`.
defaultEvents = ["change", "add", "remove", "reset", "destroy",
"sync", "error", "sort", "request"];
"sync", "error", "sort", "request"];

// Backbone.AssociatedModel
// --------------
Expand All @@ -48,16 +48,13 @@
_proxyCalls: undefined,

// Get the value of an attribute.
get: function(attr){
get: function (attr){
return this.getAttr.apply(this, arguments);
},

// Set a hash of model attributes on the object,
// fire Backbone `event` with options.
// It maintains relations between models during the set operation.
// It also bubbles up child events to the parent.
// Set a hash of model attributes on the Backbone Model.
set: function (key, value, options) {
var attributes, processedRelations, tbp, attr;
var attributes, attr, modelMap, modelId, obj, result = this;
// Duplicate backbone's behavior to allow separate key/value parameters,
// instead of a single 'attributes' object.
if (_.isObject(key) || key == null) {
Expand All @@ -67,9 +64,36 @@
attributes = {};
attributes[key] = value;
}
if (!attributes) return this;
for (attr in attributes) {
var pathTokens = getPathArray(attr), initials = _.initial(pathTokens), last = _.last(pathTokens),
root = this, parentModel = this.get(initials);

modelMap || (modelMap = {});
if ((!parentModel && _.size(initials) > 0) || parentModel instanceof BackboneCollection) continue;
parentModel instanceof AssociatedModel && (root = parentModel);
obj = modelMap[root.cid] || (modelMap[root.cid] = {'model': root, 'data': {}});
obj.data[last] = attributes[attr];
}
if (modelMap) {
for (modelId in modelMap) {
obj = modelMap[modelId];
this.setAttr.call(obj.model, obj.data, options) || (result = false);
}
} else {
result = this.setAttr.call(this, attributes, options);
}
return result;
},

// Set a hash of model attributes on the object,
// fire Backbone `event` with options.
// It maintains relations between models during the set operation.
// It also bubbles up child events to the parent.
setAttr: function (attributes, options) {
var processedRelations, tbp, attr;
// Extract attributes and options.
options || (options = {});
if (!attributes) return this;
if (options.unset) for (attr in attributes) attributes[attr] = void 0;

if (this.relations) {
Expand Down Expand Up @@ -168,13 +192,13 @@
if (relationValue instanceof BackboneCollection && "change" === eventType && eventObject) {
//indexEventObject = _.indexOf(relationValue.models, eventObject);
var pathTokens = getPathArray(eventPath),
initialTokens = _.initial(pathTokens),
colModel;
initialTokens = _.initial(pathTokens), colModel;

colModel = relationValue.find(function (model) {
var changedModel = model.get(pathTokens);
return eventObject === !(changedModel instanceof AssociatedModel
|| changedModel instanceof BackboneCollection)
? model.get(initialTokens) : changedModel;
return eventObject === (changedModel instanceof AssociatedModel
|| changedModel instanceof BackboneCollection)
? changedModel : (model.get(initialTokens) || model);
});
colModel && (indexEventObject = relationValue.indexOf(colModel));
}
Expand Down Expand Up @@ -343,7 +367,7 @@

// Create a new model with identical attributes to this one.
clone: function () {
return new this.constructor(this.toJSON());
return new this.constructor(this.toJSON());
},

// Get `reduced` result using passed `path` array or string.
Expand All @@ -352,6 +376,7 @@
attrs = getPathArray(path),
key,
i;
if (_.size(attrs) < 1) return;
iterator || (iterator = function (memo, key) {
return memo instanceof BackboneCollection && _.isNumber(key) ? memo.at(key) : memo.attributes[key];
});
Expand All @@ -365,15 +390,13 @@
});

// Get Path `attrs` as Array
// Example:
// 'employee.works_for.locations[2].name' -> ['employee', 'works_for', 'locations', 2, 'name']
var getPathArray = function (path, iterator, context) {
if (_.isString(path)) {
iterator || (iterator = function (value) {
return value.match(/^\d+$/) ? parseInt(value, 10) : value;
});
return _.map(path.match(/[^\.\[\]]+/g) || [], iterator, context);
return _.map(path.match(/[^\.\[\]]+/g) || [''], iterator, context);
}
return path || [];
return path || [''];
}
})();

0 comments on commit c48c2d1

Please sign in to comment.