Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 492 lines (363 sloc) 21.147 kb
6211bed @PaulUithol More tests, expanded readme
authored
1 # Backbone-relational
e2b2776 @PaulUithol Update the readme/documentation
authored
2 Backbone-relational provides one-to-one, one-to-many and many-to-one relations between models for [Backbone](https://github.com/documentcloud/backbone). To use relations, extend `Backbone.RelationalModel` (instead of the regular `Backbone.Model`) and define a property `relations`, containing an array of option objects. Each relation must define (as a minimum) the `type`, `key` and `relatedModel`. Available relation types are `Backbone.HasOne` and `Backbone.HasMany`. Backbone-relational features:
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
3
e2b2776 @PaulUithol Update the readme/documentation
authored
4 * Bidirectional relations, which notify related models of changes through events.
5 * Control how relations are serialized using the `includeInJSON` option.
6 * Automatically convert nested objects in a model's attributes into Model instances using the `createModels` option.
7 * Retrieve (a set of) related models through the `fetchRelated(key<string>, [options<object>])` method.
8 * Determine the type of `HasMany` collections with `collectionType`.
9 * Bind new events to a `Backbone.RelationalModel` for:
10 * addition to a `HasMany` relation (bind to `add:<key>`; arguments: `(addedModel, relatedCollection)`),
11 * removal from a `HasMany` relation (bind to `remove:<key>`; arguments: `(removedModel, relatedCollection)`),
1464889 @PaulUithol Also proxy 'reset' events from a 'HasMany' to the relation owner; docume...
authored
12 * reset of a `HasMany` relation (bind to `reset:<key>`; arguments: `(relatedCollection)`),
e2b2776 @PaulUithol Update the readme/documentation
authored
13 * changes to the key itself on `HasMany` and `HasOne` relations (bind to `update:<key>`; arguments=`(model, relatedModel/relatedCollection)`).
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
14
e2b2776 @PaulUithol Update the readme/documentation
authored
15 ## Contents
bcdf788 @PaulUithol Update backbone.js & underscore.js dependencies
authored
16
954b9b3 @PaulUithol Add tutorial link (fixes #77); explain issues with CoffeeScript inherita...
authored
17 * [Getting started](#getting-started)
e2b2776 @PaulUithol Update the readme/documentation
authored
18 * [Backbone.Relation options](#backbone-relation)
19 * [Backbone.RelationalModel](#backbone-relationalmodel)
20 * [Example](#example)
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
21 * [Known problems and solutions](#q-and-a)
e2b2776 @PaulUithol Update the readme/documentation
authored
22 * [Under the hood](#under-the-hood)
bcdf788 @PaulUithol Update backbone.js & underscore.js dependencies
authored
23
954b9b3 @PaulUithol Add tutorial link (fixes #77); explain issues with CoffeeScript inherita...
authored
24
25 ## <a name="getting-started"/>Getting started
26
27 Resources to get you started with Backbone-relational:
28
e7d0ac3 @PaulUithol Small fixes to the readme
authored
29 * [A great tutorial by antoviaque](http://antoviaque.org/docs/tutorials/backbone-relational-tutorial/) ([and the accompanying git repository](https://github.com/antoviaque/backbone-relational-tutorial))
954b9b3 @PaulUithol Add tutorial link (fixes #77); explain issues with CoffeeScript inherita...
authored
30
31
32 ### <a name="installation"/>Installation
bcdf788 @PaulUithol Update backbone.js & underscore.js dependencies
authored
33
e2b2776 @PaulUithol Update the readme/documentation
authored
34 Backbone-relational depends on [backbone](https://github.com/documentcloud/backbone) (and thus on [underscore](https://github.com/documentcloud/underscore)). Include Backbone-relational right after Backbone and Underscore:
bcdf788 @PaulUithol Update backbone.js & underscore.js dependencies
authored
35
c5af076 @PaulUithol Fix the 'fetch' example by including a reset; use html syntax highlighti...
authored
36 ```html
e2b2776 @PaulUithol Update the readme/documentation
authored
37 <script type="text/javascript" src="./js/underscore.js"></script>
38 <script type="text/javascript" src="./js/backbone.js"></script>
39 <script type="text/javascript" src="./js/backbone-relational.js"></script>
40 ```
41
ee93a40 @DouweM Update backbone.js used for testing to version 0.9.2.
DouweM authored
42 Backbone-relational has been tested with Backbone 0.9.2 (or newer) and Underscore 1.3.1 (or newer).
e2b2776 @PaulUithol Update the readme/documentation
authored
43
954b9b3 @PaulUithol Add tutorial link (fixes #77); explain issues with CoffeeScript inherita...
authored
44
e2b2776 @PaulUithol Update the readme/documentation
authored
45 ## <a name="backbone-relation"/>Backbone.Relation options
46
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
47 Each `Backbone.RelationalModel` can contain an array of `relations`.
48 Each relation supports a number of options, of which `relatedModel`, `key` and `type` are mandatory.
49 A relation could look like the following:
e2b2776 @PaulUithol Update the readme/documentation
authored
50
51 ```javascript
52 Zoo = Backbone.RelationalModel.extend({
53 relations: [{
54 type: Backbone.HasMany,
55 key: 'animals',
56 relatedModel: 'Animal',
57 collectionType: 'AnimalCollection',
58 reverseRelation: {
59 key: 'livesIn',
60 includeInJSON: 'id'
61 // 'relatedModel' is automatically set to 'Zoo'; the 'relationType' to 'HasOne'.
a02654c @PaulUithol Expand example with a 'toJSON' call
authored
62 }
e2b2776 @PaulUithol Update the readme/documentation
authored
63 }]
64 });
65
66 Animal = Backbone.RelationalModel.extend({
67 urlRoot: '/animal/'
68 });
69
70 AnimalCollection = Backbone.Collection.extend({
71 model: Animal,
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
72
e2b2776 @PaulUithol Update the readme/documentation
authored
73 url: function( models ) {
74 return '/animal/' + ( models ? 'set/' + _.pluck( models, 'id' ).join(';') + '/' : '' );
75 }
76 });
67a415a @PaulUithol syntax highlighting in the readme
authored
77 ```
6211bed @PaulUithol More tests, expanded readme
authored
78
e2b2776 @PaulUithol Update the readme/documentation
authored
79 ### relatedModel
80
81 Value: a string (which can be resolved to an object type on the global scope), or a reference to a `Backbone.RelationalModel` type.
82
83 ### key
84
85 Value: a string. References an attribute name on `relatedModel`.
86
87 ### type
88
89 Value: a string, or a reference to a `Backbone.Relation` type
90
91 Example: `Backbone.HasOne` or `'HasMany'`.
92
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
93 ###### **HasOne relations (`Backbone.HasOne`)**
e2b2776 @PaulUithol Update the readme/documentation
authored
94
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
95 The key for a `HasOne` relation consists of a single `Backbone.RelationalModel`. The default `reverseRelation.type` for a HasOne relation is HasMany.
96 This can be set to `HasOne` instead, to create a one-to-one relation.
e2b2776 @PaulUithol Update the readme/documentation
authored
97
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
98 ###### **HasMany relations (`Backbone.HasMany`)**
e2b2776 @PaulUithol Update the readme/documentation
authored
99
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
100 The key for a `HasMany` relation consists of a `Backbone.Collection`, containing zero or more `Backbone.RelationalModel`s.
101 The default `reverseRelation.type` for a HasMany relation is HasOne; this is the only option here, since many-to-many is not supported directly.
e2b2776 @PaulUithol Update the readme/documentation
authored
102
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
103 ###### **<a name="many-to-many"/>Many-to-many relations**
e2b2776 @PaulUithol Update the readme/documentation
authored
104 A many-to-many relation can be modeled using two `Backbone.HasMany` relations, with a link model in between:
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
105
67a415a @PaulUithol syntax highlighting in the readme
authored
106 ```javascript
e2b2776 @PaulUithol Update the readme/documentation
authored
107 Person = Backbone.RelationalModel.extend({
108 relations: [
109 {
110 type: 'HasMany',
111 key: 'jobs',
1a09e6d @PaulUithol Added a note about the use of 'reverseRelation'
authored
112 relatedModel: 'Job',
e2b2776 @PaulUithol Update the readme/documentation
authored
113 reverseRelation: {
114 key: 'person'
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
115 }
e2b2776 @PaulUithol Update the readme/documentation
authored
116 }
117 ]
118 });
119
120 // A link object between 'Person' and 'Company', to achieve many-to-many relations.
1a09e6d @PaulUithol Added a note about the use of 'reverseRelation'
authored
121 Job = Backbone.RelationalModel.extend({
e2b2776 @PaulUithol Update the readme/documentation
authored
122 defaults: {
123 'startDate': null,
124 'endDate': null
125 }
126 })
127
128 Company = Backbone.RelationalModel.extend({
129 relations: [
130 {
131 type: 'HasMany',
132 key: 'employees',
1a09e6d @PaulUithol Added a note about the use of 'reverseRelation'
authored
133 relatedModel: 'Job',
e2b2776 @PaulUithol Update the readme/documentation
authored
134 reverseRelation: {
135 key: 'company'
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
136 }
137 }
e2b2776 @PaulUithol Update the readme/documentation
authored
138 ]
139 });
140
141 niceCompany = new Company( { name: 'niceCompany' } );
142 niceCompany.bind( 'add:employees', function( model, coll ) {
1a09e6d @PaulUithol Added a note about the use of 'reverseRelation'
authored
143 // Will see a Job with attributes { person: paul, company: niceCompany } being added here
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
144 });
e2b2776 @PaulUithol Update the readme/documentation
authored
145
146 paul.get('jobs').add( { company: niceCompany } );
67a415a @PaulUithol syntax highlighting in the readme
authored
147 ```
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
148
464cdbb @PaulUithol Document the `keySource` option
authored
149 ### keySource
150
151 Value: a string. References an attribute on the data used to instantiate `relatedModel`.
152
153 Used to override `key` when determining what data to use when (de)serializing a relation, since the data backing your relations may use different naming conventions.
154 For example, a Rails backend may provide the keys suffixed with `_id` or `_ids`. The behavior for `keySource` corresponds to the following rules:
155
156 1. When a relation is instantiated, the contents of the `keySource` are used as it's initial data.
157 2. The application uses the regular `key` attribute to interface with the relation and the models in it; the `keySource` is not available as an attribute for the model.
158
159 So you may be provided with data containing `animal_ids`, while you want to access this relation as `zoo.get( 'animals' );`.
6d59955 @DouweM Add `keyDestination` option.
DouweM authored
160
161 **NOTE**: for backward compatibility reasons, setting `keySource` will set `keyDestination` as well.
162 This means that when saving `zoo`, the `animals` attribute will be serialized back into the `animal_ids` key.
464cdbb @PaulUithol Document the `keySource` option
authored
163
e7d0ac3 @PaulUithol Small fixes to the readme
authored
164 **WARNING**: when using a `keySource`, you should not use that attribute name for other purposes.
464cdbb @PaulUithol Document the `keySource` option
authored
165
6d59955 @DouweM Add `keyDestination` option.
DouweM authored
166 ### keyDestination
167
168 Value: a string. References an attribute to serialize `relatedModel` into.
169
170 Used to override `key` (and `keySource`) when determining what attribute to be written into when serializing a relation, since the server backing your relations may use different naming conventions.
171 For example, a Rails backend may expect the keys to be suffixed with `_attributes` for nested attributes.
172
173 When calling `toJSON` on a model (either via `Backbone.sync`, or directly), the data in the `key` attribute is transformed and assigned to the `keyDestination`.
174
175 So you may want a relation to be serialized into the `animals_attributes` key, while you want to access this relation as `zoo.get( 'animals' );`.
176
e7d0ac3 @PaulUithol Small fixes to the readme
authored
177 **WARNING**: when using a `keyDestination`, you should not use that attribute name for other purposes.
6d59955 @DouweM Add `keyDestination` option.
DouweM authored
178
e2b2776 @PaulUithol Update the readme/documentation
authored
179 ### collectionType
180
181 Value: a string (which can be resolved to an object type on the global scope), or a reference to a `Backbone.Collection` type.
6211bed @PaulUithol More tests, expanded readme
authored
182
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
183 Determine the type of collections used for a `HasMany` relation. If you define a `url(models<Backbone.Model[]>)` function on
184 the specified collection, this enables `fetchRelated` to fetch all missing models in one request, instead of firing a separate request for each.
185 See [Backbone-tastypie](https://github.com/PaulUithol/backbone-tastypie/blob/master/backbone_tastypie/static/js/backbone-tastypie.js#L92) for an example
186 of a `url` function that can build a url for the collection (or a subset of models).
6211bed @PaulUithol More tests, expanded readme
authored
187
51b77c0 @singingwolfboy Add documentation for option
singingwolfboy authored
188 ### collectionKey
189
190 Value: a string or a boolean
191
464cdbb @PaulUithol Document the `keySource` option
authored
192 Used to create a back reference from the `Backbone.Collection` used for a `HasMany` relation to the model on the other side of this relation.
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
193 By default, the relation's `key` attribute will be used to create a reference to the RelationalModel instance from the generated collection.
194 If you set `collectionKey` to a string, it will use that string as the reference to the RelationalModel, rather than the relation's `key` attribute.
464cdbb @PaulUithol Document the `keySource` option
authored
195 If you don't want this behavior at all, set `collectionKey` to false (or any falsy value) and this reference will not be created.
51b77c0 @singingwolfboy Add documentation for option
singingwolfboy authored
196
c3ddc6a @ulmus Changed to collectionOptions and accepts an options hash or a function
ulmus authored
197 ### collectionOptions
f30e47f @ulmus Added collectionOptionsCallback option on ToMany options
ulmus authored
198
c3ddc6a @ulmus Changed to collectionOptions and accepts an options hash or a function
ulmus authored
199 Value: an options hash or a function that accepts an instance of a `Backbone.RelationalModed` and returns an option hash
f30e47f @ulmus Added collectionOptionsCallback option on ToMany options
ulmus authored
200
c3ddc6a @ulmus Changed to collectionOptions and accepts an options hash or a function
ulmus authored
201 Used to provide options for the initialization of the collection in the "Many"-end of a `HasMany` relation. Can be an options hash or
202 a function that should take the instance in the "One"-end of the "HasMany" relation and return an options hash
f30e47f @ulmus Added collectionOptionsCallback option on ToMany options
ulmus authored
203
e2b2776 @PaulUithol Update the readme/documentation
authored
204 ### includeInJSON
6211bed @PaulUithol More tests, expanded readme
authored
205
7f2ad14 @PaulUithol Fix a race condition during the setup of a 'reverseRelation'. The revers...
authored
206 Value: a boolean, or a string referencing one of the model's attributes. Default: `true`.
6211bed @PaulUithol More tests, expanded readme
authored
207
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
208 Determines how a relation will be serialized following a call to the `toJSON` method. A value of `true` serializes the full set of attributes
209 on the related model(s), in which case the relations of this object are serialized as well. Set to `false` to exclude the relation completely.
210 You can also choose to include a single attribute from the related model by using a string.
211 For example, `'name'`, or `Backbone.Model.prototype.idAttribute` to include ids.
6211bed @PaulUithol More tests, expanded readme
authored
212
e2b2776 @PaulUithol Update the readme/documentation
authored
213 ### createModels
214
215 Value: a boolean. Default: `true`.
216
7f2ad14 @PaulUithol Fix a race condition during the setup of a 'reverseRelation'. The revers...
authored
217 Should models be created from nested objects, or not?
e2b2776 @PaulUithol Update the readme/documentation
authored
218
219 ### reverseRelation
220
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
221 If the relation should be bidirectional, specify the details for the reverse relation here.
222 It's only mandatory to supply a `key`; `relatedModel` is automatically set. The default `type` for a `reverseRelation` is `HasMany` for a `HasOne` relation (which can be overridden to `HasOne` in order to create a one-to-one relation), and `HasOne` for a `HasMany` relation. In this case, you cannot create a reverseRelation with type `HasMany` as well; please see [Many-to-many relations](#many-to-many) on how to model these type of relations.
e2b2776 @PaulUithol Update the readme/documentation
authored
223
1a09e6d @PaulUithol Added a note about the use of 'reverseRelation'
authored
224 **Please note**: if you define a relation (plus a `reverseRelation`) on a model, but never actually create an instance of that model, the model's `constructor` will never run, which means it's `initializeRelations` will never get called, and the reverseRelation will not be initialized either. In that case, you could either define the relation on the opposite model, or define two single relations. See [issue 20](https://github.com/PaulUithol/Backbone-relational/issues/20) for a discussion.
225
e2b2776 @PaulUithol Update the readme/documentation
authored
226 ## <a name="backbone-relationalmodel"/>Backbone.RelationalModel
227
228 `Backbone.RelationalModel` introduces a couple of new methods and events.
229
230 ### Methods
231
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
232 ###### **getRelations `relationalModel.getRelations()`**
e2b2776 @PaulUithol Update the readme/documentation
authored
233
234 Returns the set of initialized relations on the model.
235
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
236 ###### **fetchRelated `relationalModel.fetchRelated(key<string>, [options<object>])`**
e2b2776 @PaulUithol Update the readme/documentation
authored
237
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
238 Fetch models from the server that were referenced in the model's attributes, but have not been found/created yet.
239 This can be used specifically for lazy-loading scenarios.
7f2ad14 @PaulUithol Fix a race condition during the setup of a 'reverseRelation'. The revers...
authored
240
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
241 By default, a separate request will be fired for each additional model that is to be fetched from the server.
242 However, if your server/API supports it, you can fetch the set of models in one request by specifying a `collectionType`
243 for the relation you call `fetchRelated` on. The `collectionType` should have an overridden `url(models<Backbone.Model[]>)`
244 method that allows it to construct a url for an array of models.
245 See the example at the top of [Backbone.Relation options](#backbone-relation) or
246 [Backbone-tastypie](https://github.com/PaulUithol/backbone-tastypie/blob/master/backbone_tastypie/static/js/backbone-tastypie.js#L92) for an example.
e2b2776 @PaulUithol Update the readme/documentation
authored
247
248 ### Events
249
250 * `add`: triggered on addition to a `HasMany` relation.
251 Bind to `add:<key>`; arguments: `(addedModel<Backbone.Model>, related<Backbone.Collection>)`.
252 * `remove`: triggered on removal from a `HasMany` relation.
253 Bind to `remove:<key>`; arguments: `(removedModel<Backbone.Model>, related<Backbone.Collection>)`.
254 * `update`: triggered on changes to the key itself on `HasMany` and `HasOne` relations.
255 Bind to `update:<key>`; arguments: `(model<Backbone.Model>, related<Backbone.Model|Backbone.Collection>)`.
256
7585491 @DouweM Add documentation to README for `partOfSupermodel`, `submodelType` and `...
DouweM authored
257 ### Properties
258
259 Properties can be defined along with the subclass prototype when extending `Backbone.RelationalModel` or a subclass thereof.
260
261 ###### <a name="property-part-of-supermodel" />**partOfSupermodel**
262
263 Value: a boolean. Default: `false`.
264
265 Determines whether this model should be considered a proper submodel of its
266 superclass (the model type you're extending), with a shared id pool.
267
268 This means that when looking for an object of the supermodel's type, objects
269 of this submodel's type could be returned as well, as long as the id matches.
270 In effect, any relations pointing to the supermodel will look for objects
271 of the supermodel's submodel's types as well.
272
273 Suppose that we have an `Animal` model and a `Dog` model extending `Animal`
274 with `partOfSupermodel` set to `true`. If we have a `Dog` object with id `3`,
275 this object will be returned when we have a relation pointing to an `Animal`
276 with id `3`, as `Dog` is regarded a specific kind of `Animal`: it's just an
277 `Animal` with possibly some dog-specific properties or methods.
278
279 Note that this means that there cannot be any overlap in ids between instances
280 of classes `Animal` and `Dog`, as the `Dog` with id `3` will *be* the `Animal`
281 with id `3`.
282
283 ###### <a name="property-submodel-type" />**submodelType**
284
285 Value: a string.
286
287 When building a model instance for a relation with a `relatedModel` that has
288 one or more submodels (i.e. models that have
289 [`partOfSupermodel`](#property-part-of-supermodel) set to true), we need to
290 determine what kind of object we're dealing with and an instance of what
291 submodel should be built. This is done by finding the `relatedModel`'s
292 submodel for which the `submodelType` is equal to the value of the
293 [`submodelTypeAttribute`](#property-submodel-type-attribute) attribute on the
294 newly passed in data object.
295
296 ###### <a name="property-submodel-type-attribute" />**submodelTypeAttribute**
297
298 Value: a string. References an attribute on the data used to instantiate
299 `relatedModel`. Default: `"type"`.
300
301 The attribute that will be checked to determine the type of model that
302 should be built when a raw object of attributes is set as the related value,
303 and if the `relatedModel` has one or more submodels.
304
305 See [`submodelType`](#property-submodel-type) for more information.
306
e2b2776 @PaulUithol Update the readme/documentation
authored
307 ## <a name="example"/>Example
6211bed @PaulUithol More tests, expanded readme
authored
308
67a415a @PaulUithol syntax highlighting in the readme
authored
309 ```javascript
e2b2776 @PaulUithol Update the readme/documentation
authored
310 paul = new Person({
311 id: 'person-1',
312 name: 'Paul',
313 user: { id: 'user-1', login: 'dude', email: 'me@gmail.com' }
314 });
315
316 // A User object is automatically created from the JSON; so 'login' returns 'dude'.
317 paul.get('user').get('login');
318
319 ourHouse = new House({
320 id: 'house-1',
321 location: 'in the middle of the street',
322 occupants: ['person-1', 'person-2', 'person-5']
323 });
324
325 // 'ourHouse.occupants' is turned into a Backbone.Collection of Persons.
326 // The first person in 'ourHouse.occupants' will point to 'paul'.
9603ede @PaulUithol Fix a small error in the readme's example
authored
327 ourHouse.get('occupants').at(0); // === paul
e2b2776 @PaulUithol Update the readme/documentation
authored
328
4789cb0 @singingwolfboy Added documentation for collectionKey to example section of README
singingwolfboy authored
329 // If a collection is created from a HasMany relation, it contains a reference
330 // back to the originator of the relation
331 ourHouse.get('occupants').livesIn; // === ourHouse
332
e2b2776 @PaulUithol Update the readme/documentation
authored
333 // the relation from 'House.occupants' to 'Person' has been defined as a bi-directional HasMany relation,
334 // with a reverse relation to 'Person.livesIn'. So, 'paul.livesIn' will automatically point back to 'ourHouse'.
335 paul.get('livesIn'); // === ourHouse
336
337 // You can control which relations get serialized to JSON (when saving), using the 'includeInJSON'
338 // property on a Relation. Also, each object will only get serialized once to prevent loops.
339 paul.get('user').toJSON();
340 /* result:
341 {
342 email: "me@gmail.com",
343 id: "user-1",
344 login: "dude",
345 person: {
346 id: "person-1",
347 name: "Paul",
348 livesIn: {
349 id: "house-1",
350 location: "in the middle of the street",
351 occupants: ["person-1"] // just the id, since 'includeInJSON' references the 'idAttribute'
352 },
353 user: "user-1" // not serialized because it is already in the JSON, so we won't create a loop
6211bed @PaulUithol More tests, expanded readme
authored
354 }
e2b2776 @PaulUithol Update the readme/documentation
authored
355 }
356 */
357
358 // Load occupants 'person-2' and 'person-5', which don't exist yet, from the server
359 ourHouse.fetchRelated( 'occupants' );
360
361 // Use the 'add' and 'remove' events to listen for additions/removals on HasMany relations (like 'House.occupants').
362 ourHouse.bind( 'add:occupants', function( model, coll ) {
363 // create a View?
364 console.debug( 'add %o', model );
6211bed @PaulUithol More tests, expanded readme
authored
365 });
e2b2776 @PaulUithol Update the readme/documentation
authored
366 ourHouse.bind( 'remove:occupants', function( model, coll ) {
367 // destroy a View?
368 console.debug( 'remove %o', model );
369 });
370
371 // Use the 'update' event to listen for changes on a HasOne relation (like 'Person.livesIn').
372 paul.bind( 'update:livesIn', function( model, attr ) {
373 console.debug( 'update to %o', attr );
374 });
375
376
377 // Modifying either side of a bi-directional relation updates the other side automatically.
378 // Make paul homeless; triggers 'remove:occupants' on ourHouse, and 'update:livesIn' on paul
379 ourHouse.get('occupants').remove( paul.id );
380
381 paul.get('livesIn'); // yup; nothing.
382
383 // Move back in; triggers 'add:occupants' on ourHouse, and 'update:livesIn' on paul
384 paul.set( { 'livesIn': 'house-1' } );
385 ```
386
387 This is achieved using the following relations and models:
388
389 ```javascript
390 House = Backbone.RelationalModel.extend({
391 // The 'relations' property, on the House's prototype. Initialized separately for each instance of House.
392 // Each relation must define (as a minimum) the 'type', 'key' and 'relatedModel'. Options are
393 // 'includeInJSON', 'createModels' and 'reverseRelation', which takes the same options as the relation itself.
394 relations: [
395 {
396 type: Backbone.HasMany, // Use the type, or the string 'HasOne' or 'HasMany'.
397 key: 'occupants',
398 relatedModel: 'Person',
399 includeInJSON: Backbone.Model.prototype.idAttribute,
400 collectionType: 'PersonCollection',
401 reverseRelation: {
402 key: 'livesIn'
403 }
6211bed @PaulUithol More tests, expanded readme
authored
404 }
e2b2776 @PaulUithol Update the readme/documentation
authored
405 ]
406 });
407
408 Person = Backbone.RelationalModel.extend({
409 relations: [
410 { // Create a (recursive) one-to-one relationship
411 type: Backbone.HasOne,
412 key: 'user',
413 relatedModel: 'User',
414 reverseRelation: {
415 type: Backbone.HasOne,
416 key: 'person'
6211bed @PaulUithol More tests, expanded readme
authored
417 }
e2b2776 @PaulUithol Update the readme/documentation
authored
418 }
419 ],
6211bed @PaulUithol More tests, expanded readme
authored
420
e2b2776 @PaulUithol Update the readme/documentation
authored
421 initialize: function() {
422 // do whatever you want :)
423 }
424 });
425
426 PersonCollection = Backbone.Collection.extend({
427 url: function( models ) {
428 // Logic to create a url for the whole collection, or a set of models.
429 // See the tests, or Backbone-tastypie, for an example.
430 return '/person/' + ( models ? 'set/' + _.pluck( models, 'id' ).join(';') + '/' : '' );
431 }
432 });
433
434 User = Backbone.RelationalModel.extend();
67a415a @PaulUithol syntax highlighting in the readme
authored
435 ```
6211bed @PaulUithol More tests, expanded readme
authored
436
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
437 ## <a name="q-and-a"/>Known problems and solutions
438
954b9b3 @PaulUithol Add tutorial link (fixes #77); explain issues with CoffeeScript inherita...
authored
439 > **Q:** (Reverse) relations don't seem to be initialized properly (and I'm using Coffeescript!)
440
441 **A:** You're probably using the syntax `class MyModel extends Backbone.RelationalModel` instead of `MyModel = Backbone.RelationalModel.extend`.
442 This has advantages in CoffeeScript, but it also means that `Backbone.Model.extend` will not get called.
443 Instead, CoffeeScript generates piece of code that would normally achieve roughly the same.
444 However, `extend` is also the method that Backbone-relational overrides to set up relations as soon as your code gets parsed by the JavaScript engine.
445
446 A possible solution is to initialize a blank placeholder model right after defining a model that contains reverseRelations; this will also bootstrap the relations. For example:
447
448 ```javascript
449 class MyModel extends Backbone.RelationalModel
450 relations: [
451 // etc
452 ]
453
454 new MyModel
455 ```
456
457 See [issue #91](https://github.com/PaulUithol/Backbone-relational/issues/91) for more information and workarounds.
458
459 > **Q:** After a fetch, I don't get `add:<key>` events for nested relations.
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
460
954b9b3 @PaulUithol Add tutorial link (fixes #77); explain issues with CoffeeScript inherita...
authored
461 **A:** This is due to `Backbone.Collection.reset` silencing add events. Pass `fetch( {add: true} )` to bypass this problem.
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
462 You may want to override `Backbone.Collection.fetch` for this, and also trigger an event when the fetch has finished while you're at it.
463 Example:
464
465 ```javascript
466 var _fetch = Backbone.Collection.prototype.fetch;
467 Backbone.Collection.prototype.fetch = function( options ) {
468 options || ( options = {} );
469 _.defaults( options, { add: true } );
470
c5af076 @PaulUithol Fix the 'fetch' example by including a reset; use html syntax highlighti...
authored
471 // Remove old models
472 this.reset();
473
474 // Call 'fetch', and trigger an event when done.
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
475 var dit = this,
476 request = _fetch.call( this, options );
477 request.done( function() {
478 if ( !options.silent ) {
479 dit.trigger( 'fetch', dit, options );
480 }
481 });
482
483 return request;
484 };
485 ```
486
e2b2776 @PaulUithol Update the readme/documentation
authored
487 ## <a name="under-the-hood"/>Under the hood
37affc3 @PaulUithol Initial commit; Backbone.RelationalModel, HasOne and HasMany.
authored
488
530059d @PaulUithol Documentation update; add a 'known problems and solutions' section, cope...
authored
489 Each `Backbone.RelationalModel` registers itself with `Backbone.Store` upon creation (and is removed from the `Store` when destroyed).
490 When creating or updating an attribute that is a key in a relation, removed related objects are notified of their removal,
491 and new related objects are looked up in the `Store`.
Something went wrong with that request. Please try again.