diff --git a/README.md b/README.md index ec2bec078f..60dd2152c9 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ List of Definitions * [AngularJS](http://angularjs.org) (by [Diego Vilar](https://github.com/diegovilar)) ([wiki](https://github.com/borisyankov/DefinitelyTyped/wiki/AngularJS-Definitions-Usage-Notes)) * [async](https://github.com/caolan/async) (by [Boris Yankov](https://github.com/borisyankov)) * [Backbone.js](http://backbonejs.org/) (by [Boris Yankov](https://github.com/borisyankov)) +* [Backbone Relational](http://backbonerelational.org/) (by [Eirik Hoem](https://github.com/eirikhm)) * [Bootbox](https://github.com/makeusabrew/bootbox) (by [Vincent Bortone](https://github.com/vbortone/)) * [Bootstrap](http://twitter.github.com/bootstrap/) (by [Boris Yankov](https://github.com/borisyankov)) * [bootstrap-notify](https://github.com/Nijikokun/bootstrap-notify) (by [Blake Niemyjski](https://github.com/niemyjski)) diff --git a/backbone-relational/backbone-relational-test.ts b/backbone-relational/backbone-relational-test.ts new file mode 100644 index 0000000000..f1eaffc020 --- /dev/null +++ b/backbone-relational/backbone-relational-test.ts @@ -0,0 +1,121 @@ +/// +/// + +class House extends Backbone.RelationalModel { + // The 'relations' property, on the House's prototype. Initialized separately for each + // instance of House. Each relation must define (as a minimum) the 'type', 'key' and + // 'relatedModel'. Options include 'includeInJSON', 'createModels' and 'reverseRelation'. + + relations = [ + { + type: Backbone.HasMany, // Use the type, or the string 'HasOne' or 'HasMany'. + key: 'occupants', + relatedModel: 'Person', + includeInJSON: Backbone.Model.prototype.idAttribute, + collectionType: 'PersonCollection', + reverseRelation: { + key: 'livesIn' + } + } + ]; + +} + +class Person extends Backbone.RelationalModel { + relations = [ + { // Create a (recursive) one-to-one relationship + type: Backbone.HasOne, + key: 'user', + relatedModel: 'User', + reverseRelation: { + type: Backbone.HasOne, + key: 'person' + } + } + ]; + + initialize() + { + // do whatever you want :) + } +} + +class PersonCollection extends Backbone.Collection { + url(models) + { + // Logic to create a url for the whole collection, or a set of models. + // See the tests, or Backbone-tastypie, for an example. + return '/person/' + ( models ? 'set/' + _.pluck(models, 'id').join(';') + '/' : '' ); + } +} + +class User extends Backbone.RelationalModel { + +} + + +var paul = new Person({ + id: 'person-1', + name: 'Paul', + user: { id: 'user-1', login: 'dude', email: 'me@gmail.com' } +}); + +// A User object is automatically created from the JSON; so 'login' returns 'dude'. +paul.get('user').get('login'); + +var ourHouse = new House({ + id: 'house-1', + location: 'in the middle of the street', + occupants: ['person-1', 'person-2', 'person-5'] +}); + +// 'ourHouse.occupants' is turned into a Backbone.Collection of Persons. +// The first person in 'ourHouse.occupants' will point to 'paul'. +ourHouse.get('occupants').at(0); // === paul + +// If a collection is created from a HasMany relation, it contains a reference +// back to the originator of the relation +ourHouse.get('occupants').livesIn; // === ourHouse + +// The `occupants` relation on 'House' has been defined as a HasMany, with a reverse relation +// to `livesIn` on 'Person'. So, 'paul.livesIn' will automatically point back to 'ourHouse'. +paul.get('livesIn'); // === ourHouse + +// You can control which relations get serialized to JSON, using the 'includeInJSON' +// property on a Relation. Also, each object will only get serialized once to prevent loops. +alert(JSON.stringify(paul.get('user').toJSON(), null, '\t')); +// Load occupants 'person-2' and 'person-5', which don't exist yet, from the server +ourHouse.fetchRelated('occupants'); + +// Use the `add` and `remove` events to listen for additions/removals on a HasMany relation. +// Here, we listen for changes to `ourHouse.occupants`. +ourHouse + .on('add:occupants', function (model, coll) + { + console.log('add %o', model); + // Do something. Create a View? + }) + .on('remove:occupants', function (model, coll) + { + console.log('remove %o', model); + // Do somehting. Destroy a View? + }); + +// Use the 'update' event to listen for changes on a HasOne relation (like 'Person.livesIn'). +paul.on('change:livesIn', function (model, attr) +{ + console.log('change `livesIn` to %o', attr); +}); + +// Modifying either side of a bi-directional relation updates the other side automatically. +// Take `paul` out or `ourHouse`; this triggers `remove:occupants` on `ourHouse`, +// and `change:livesIn` on `paul` +ourHouse.get('occupants').remove(paul); + +alert('paul.livesIn=' + paul.get('livesIn')); +// Move into `theirHouse`; triggers 'add:occupants' on ourHouse, and 'change:livesIn' on paul + +var theirHouse = new House({ id: 'house-2' }); +paul.set({ 'livesIn': theirHouse }); + +alert('theirHouse.occupants=' + theirHouse.get('occupants').pluck('name')); \ No newline at end of file