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.js to your HTML
<!-- 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
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 (a.k.a. relations), which keeps it relatively simple. If you support for more complex relationships between models, see the Backbone plugin wiki page. There is also an open discussion about merging this project with backbone-deep-model.
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.