A plugin to make Backbone.js keep track of nested attributes.
Suppose you have a Backbone Model with nested attributes, perhaps to remain consistent with your document-oriented database. Updating the nested attribute won't cause the model's
"change" event to fire, which is confusing.
var user =name:first: 'Aidan'last: 'Feldman';userbind'change'// this is never reached!;userget'name'first = 'Bob';usersave;
Wouldn't it be awesome if you could do this?
Install the latest version:bower install backbone backbone-nested-model jquery underscore --save
backbone-nested.jsto your HTML
<head>:<!-- must loaded in this order -->
Download the latest release and the dependencies listed above, then include with script tags in your HTML.
Change your models to extend from
Backbone.NestedModel, e.g.var Person = BackboneModelextend ;// becomesvar Person = BackboneNestedModelextend ;
Change your getters and setters to not access nested attributes directly, e.g.userget'name'first = 'Bob';// becomesuserset'name.first': 'Bob';
Best of all,
Backbone.NestedModel is designed to be a backwards-compatible, drop-in replacement of
Backbone.Model, so the switch can be made painlessly.
set() will work as before, but nested attributes should be accessed using the Backbone-Nested string syntax:
// dot syntaxuserset'name.first': 'Bob''name.middle.initial': 'H';userget'name.first' // returns 'Bob'userget'name.middle.initial' // returns 'H'// object syntaxuserset'name':first: 'Barack'last: 'Obama';
// object syntaxuserset'addresses':city: 'Brooklyn' state: 'NY'city: 'Oak Park' state: 'IL';userget'addresses.state' // returns 'NY'// square bracket syntaxuserset'addresses.state': 'MI';
"change" events can be bound to nested attributes in the same way, and changing nested attributes will fire up the chain:
// all of these will fire when 'name.middle.initial' is set or changeduserbind'change' ;userbind'change:name' ;userbind'change:name.middle' ;userbind'change:name.middle.initial' ;// all of these will fire when the first address is added or changeduserbind'change' ;userbind'change:addresses' ;userbind'change:addresses' ;userbind'change:addresses.city' ;
Additionally, nested arrays fire
userbind'add:addresses' ;userbind'remove:addresses' ;
set(), but appends the item to the nested array. For example:
userget'addresses'length; //=> 2useradd'addresses'city: 'Seattle'state: 'WA';userget'addresses'length; //=> 3
unset(), but if the unset item is an element in a nested array, the array will be compacted. For example:
userget'addresses'length; //=> 2userremove'addresses';userget'addresses'length; //=> 1
Note, this plugin does not handle non-embedded relations, which keeps it relatively simple. If you support for more complex relationships between models, see the Backbone plugin wiki page.
Pull requests are more than welcome - please add tests, which can be run by opening test/index.html. They can also be run from the command-line (requires PhantomJS):
$ npm install $ grunt
See also: live tests for latest release.