PageRenderTime 27ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/index.html

https://github.com/sventschui/Backbone-relational
HTML | 1663 lines | 1494 code | 158 blank | 11 comment | 0 complexity | 69ad0e913af9a87a436c298eca91ba96 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <!DOCTYPE HTML>
  2. <html xmlns="http://www.w3.org/1999/html">
  3. <head>
  4. <meta http-equiv="content-type" content="text/html;charset=UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="chrome=1">
  6. <meta name="viewport" content="width=device-width">
  7. <link rel="icon" href="static/images/favicon.ico">
  8. <link href="http://fonts.googleapis.com/css?family=Arimo" rel="stylesheet" type="text/css">
  9. <link rel="stylesheet" type="text/css" href="static/css/style.css">
  10. <title>Backbone-relational.js</title>
  11. <!--[if lt IE 9]>
  12. <script>
  13. document.createElement('header');
  14. document.createElement('nav');
  15. document.createElement('section');
  16. document.createElement('article');
  17. document.createElement('aside');
  18. document.createElement('footer');
  19. document.createElement('hgroup');
  20. </script>
  21. <![endif]-->
  22. </head>
  23. <body>
  24. <div id="sidebar">
  25. <a class="toc_title" href="#">
  26. Backbone-relational.js <span class="version">(0.8.8)</span>
  27. </a>
  28. <ul>
  29. <li class="link_out"><a href="https://github.com/PaulUithol/Backbone-relational">GitHub Repository</a></li>
  30. </ul>
  31. <a class="toc_title" href="#introduction">
  32. Introduction
  33. </a>
  34. <a class="toc_title" href="#installation">
  35. Installation
  36. </a>
  37. <a class="toc_title" href="#RelationalModel">
  38. Backbone.RelationalModel
  39. </a>
  40. <ul>
  41. <li>
  42. <a href="#RelationalModel-relations">relations</a>
  43. <ul>
  44. <li><a href="#relations-key">key</a></li>
  45. <li><a href="#relations-relatedModel">relatedModel</a></li>
  46. <li><a href="#relations-type">type</a></li>
  47. <li><a href="#relations-includeInJSON">includeInJSON</a></li>
  48. <li><a href="#relations-autoFetch">autoFetch</a></li>
  49. <li><a href="#relations-collectionType">collectionType</a></li>
  50. <li><a href="#relations-collectionKey">collectionKey</a></li>
  51. <li><a href="#relations-collectionOptions">collectionOptions</a></li>
  52. <li><a href="#relations-createModels">createModels</a></li>
  53. <li><a href="#relations-keySource">keySource</a></li>
  54. <li><a href="#relations-keyDestination">keyDestination</a></li>
  55. <li><a href="#relations-parse">parse</a></li>
  56. <li><a href="#relations-reverseRelation">reverseRelation</a></li>
  57. </ul>
  58. </li>
  59. </ul>
  60. <ul>
  61. <li><a href="#RelationalModel-subModelTypes">subModelTypes</a></li>
  62. <li><a href="#RelationalModel-subModelTypeAttribute">subModelTypeAttribute</a></li>
  63. </ul>
  64. <ul>
  65. <li><a href="#RelationalModel-getAsync">getAsync</a></li>
  66. <li><a href="#RelationalModel-getIdsToFetch">getIdsToFetch</a></li>
  67. <li><a href="#RelationalModel-getRelation">getRelation</a></li>
  68. <li><a href="#RelationalModel-getRelations">getRelations</a></li>
  69. <li><a href="#RelationalModel-set">set</a></li>
  70. <li><a href="#RelationalModel-toJSON">toJSON</a></li>
  71. </ul>
  72. <ul>
  73. <li><a href="#RelationalModel-setup">setup</a></li>
  74. <li><a href="#RelationalModel-build">build</a></li>
  75. <li><a href="#RelationalModel-findOrCreate">findOrCreate</a></li>
  76. <li><a href="#RelationalModel-find">find</a></li>
  77. <li><a href="#RelationalModel-findModel">findModel</a></li>
  78. </ul>
  79. <ul>
  80. <li><a href="#RelationalModel-events"><strong>Catalog of Events</strong></a></li>
  81. </ul>
  82. <a class="toc_title" href="#Relation">
  83. Backbone.Relation
  84. </a>
  85. <ul>
  86. <li><a href="#Relation-HasOne">HasOne</a></li>
  87. <li><a href="#Relation-HasMany">HasMany</a></li>
  88. </ul>
  89. <a class="toc_title" href="#Store">
  90. Backbone.Store
  91. </a>
  92. <ul>
  93. <li><a href="#Store-addModelScope">addModelScope</a></li>
  94. <li><a href="#Store-removeModelScope">removeModelScope</a></li>
  95. <li><a href="#Store-reset">reset</a></li>
  96. </ul>
  97. <a class="toc_title" href="#examples">
  98. Examples
  99. </a>
  100. <a class="toc_title" href="#change-log">
  101. Change Log
  102. </a>
  103. <a class="toc_title" href="#under-the-hood">
  104. Under the Hood
  105. </a>
  106. </div>
  107. <div class="container">
  108. <section>
  109. <h1>
  110. Backbone-relational.js
  111. </h1>
  112. <p>
  113. When developing any medium to large-scale web application, you often get to the point where
  114. an action by a user can cause a number of different models to change on the client and the server.
  115. </p>
  116. <p>
  117. You can try to keep updating both sides of a relation manually for every action, and individually call
  118. <q><a href="http://backbonejs.org/#Model-save">save</a></q> or <q><a href="http://backbonejs.org/#Model-fetch">fetch</a></q>
  119. on each of the changed models to sync with the server, but that quickly turns into a tedious process and
  120. results in multiple requests.
  121. </p>
  122. <p>
  123. Using Backbone-relational, we can configure relationships between our models, and sync the model and all of its related models with a single
  124. call to <q><a href="http://backbonejs.org/#Model-save">save</a></q>, <q><a href="#RelationalModel-getAsync">getAsync</a></q> or <q><a href="http://backbonejs.org/#Model-fetch">fetch()</a></q>
  125. after setting up a model's <q><a href="#RelationalModel-relations">relations</a></q>.
  126. </p>
  127. <p>
  128. Backbone-relational is hosted on <a href="https://github.com/PaulUithol/Backbone-relational">GitHub</a>,
  129. and is available under the <a href="https://github.com/PaulUithol/Backbone-relational/blob/master/LICENSE.txt">MIT license</a>.
  130. </p>
  131. <p>
  132. Thanks to <a href="http://progressiveplanning.com">Progressive Planning</a> for allowing me the time to
  133. work on Backbone-relational!
  134. </p>
  135. </section>
  136. <section id="downloads">
  137. <h2>
  138. Downloads &amp; Dependencies
  139. <span style="padding-left: 7px; font-size:11px; font-weight: normal;" class="interface">
  140. (Right-click, and use "Save As")
  141. </span>
  142. </h2>
  143. <table>
  144. <tr>
  145. <td><a class="punch" href="https://raw.github.com/PaulUithol/Backbone-relational/0.8.8/backbone-relational.js">Latest Release (0.8.8)</a></td>
  146. <td class="text"><i>~70kb. Full source, uncompressed, lots of comments.</i></td>
  147. </tr>
  148. <tr>
  149. <td><a class="punch" href="https://raw.github.com/PaulUithol/Backbone-relational/master/backbone-relational.js">Development Version</a></td>
  150. </tr>
  151. </table>
  152. <p>
  153. Backbone-relational depends on <a href="http://backbonejs.org/">Backbone.js</a> <small>(>= 1.0.0)</small>,
  154. which itself requires <a href="http://underscorejs.org">Underscore.js</a> <small>(> 1.4.4)</small> and
  155. <a href="http://jquery.com">jQuery</a> <small>(> 1.7.0)</small> or
  156. <a href="http://zeptojs.com/">Zepto</a>.
  157. </p>
  158. </section>
  159. <section id="introduction">
  160. <h2>Introduction</h2>
  161. <p>
  162. Backbone-relational.js provides one-to-one, one-to-many and many-to-one relations
  163. between models for Backbone. To use relations, extend <a href="#RelationalModel"><strong>Backbone.RelationalModel</strong></a>
  164. (instead of a regular <a href="http://backbonejs.org/#Model">Backbone.Model</a>) and define a
  165. <a href="#RelationalModel-relations"><q>relations</q></a> property, containing an array of option objects.
  166. Each relation must define (at least) the <a href="#relations-type"><q>type</q></a>, <a href="#relations-key"><q>key</q></a>,
  167. and <a href="#relations-relatedModel"><q>relatedModel</q></a>. Available relation types are
  168. <a href="#Relation-HasOne"><q>Backbone.HasOne</q></a> and <a href="#Relation-HasMany"><q>Backbone.HasMany</q></a>.
  169. </p>
  170. <p>
  171. Backbone-relational's main features include:
  172. </p>
  173. <ul>
  174. <li>
  175. Bidirectional relations, which notify related models of changes through events.
  176. </li>
  177. <li>
  178. Control how relations are serialized using the <a href="#relations-includeInJSON"><q>includeInJSON</q></a> option.
  179. </li>
  180. <li>
  181. Automatically convert nested objects in a model's attributes into model instances (using the
  182. <a href="#relations-createModels"><q>createModels</q></a> option, which is <q>true</q> by default).
  183. </li>
  184. <li>
  185. Lazily retrieve a set of related models through the <a href="#RelationalModel-getAsync"><q>getAsync</q></a>
  186. method.
  187. </li>
  188. <li>
  189. Determine the type of HasMany collections with <a href="#relations-collectionType"><q>collectionType</q></a>.
  190. </li>
  191. </ul>
  192. <p>
  193. You can also bind new events to a <strong>Backbone.RelationalModel</strong> for an:
  194. </p>
  195. <ul>
  196. <li>
  197. <strong>addition</strong> to a HasMany relation with <a href="#RelationalModel-events">add:&lt;key&gt;</a>.
  198. </li>
  199. <li>
  200. <strong>removal</strong> from a HasMany relation with <a href="#RelationalModel-events">remove:&lt;key&gt;</a>.
  201. </li>
  202. <li>
  203. <strong>reset</strong> of a HasMany relation with <a href="#RelationalModel-events">reset:&lt;key&gt;</a>.
  204. </li>
  205. <li>
  206. <strong>changes</strong> to the contents of a HasMany or HasOne relations with <a href="#RelationalModel-events">change:
  207. &lt;key&gt;</a>.
  208. </li>
  209. </ul>
  210. </section>
  211. <section id="installation">
  212. <h2>Installation</h2>
  213. <p>
  214. Backbone-relational depends on <a href="http://backbonejs.org/">Backbone.js</a> (and thus on
  215. <a href="http://underscorejs.org">Underscore.js</a>). Include Backbone-relational right after Backbone
  216. and Underscore:
  217. </p>
  218. <pre class="language-markup"><code class="language-markup"><!--
  219. -->&lt;script type="text/javascript" src="./js/underscore.js"&gt;&lt;/script&gt;
  220. <!-- -->&lt;script type="text/javascript" src="./js/backbone.js"&gt;&lt;/script&gt;
  221. <!-- -->&lt;script type="text/javascript" src="./js/backbone-relational.js"&gt;&lt;/script&gt;
  222. </code></pre>
  223. <p class="notice">
  224. Note for <strong>CoffeeScript</strong> users: due to the way the <q>extends</q> keyword is implemented in
  225. CoffeeScript, you may have to make an extra call to <a href="#RelationalModel-setup"><q>setup</q></a> for
  226. your models. See the <a href="#RelationalModel-setup"><q>setup</q></a> documentation for details.
  227. </p>
  228. </section>
  229. <section id="RelationalModel">
  230. <h2>
  231. Backbone.RelationalModel
  232. </h2>
  233. <p>
  234. When using Backbone-relational, each model defining (or receiving) <q>relations</q> must extend
  235. <strong>Backbone.RelationalModel</strong> in order to function. <strong>Backbone.RelationalModel</strong>
  236. introduces a couple of new methods, events and properties. It's important to know which are properties,
  237. which are methods of an instance, and which operate on the type itself.
  238. These three subcategories are detailed below.
  239. </p>
  240. <p>
  241. <strong>Properties</strong> can be defined when extending Backbone.RelationalModel, or a subclass thereof.
  242. </p>
  243. <ul class="small">
  244. <li><a href="#RelationalModel-relations">relations</a></li>
  245. <li><a href="#RelationalModel-subModelTypes">subModelTypes</a></li>
  246. <li><a href="#RelationalModel-subModelTypeAttribute">subModelTypeAttribute</a></li>
  247. </ul>
  248. <p>
  249. <strong>Instance methods</strong> operate on an instance of a type.
  250. </p>
  251. <ul class="small">
  252. <li><a href="#RelationalModel-getAsync">getAsync</a></li>
  253. <li><a href="#RelationalModel-getIdsToFetch">getIdsToFetch</a></li>
  254. <li><a href="#RelationalModel-getRelation">getRelation</a></li>
  255. <li><a href="#RelationalModel-getRelations">getRelations</a></li>
  256. <li><a href="#RelationalModel-set">set</a></li>
  257. <li><a href="#RelationalModel-toJSON">toJSON</a></li>
  258. </ul>
  259. <p>
  260. <strong>Static methods</strong> operate on the type itself, as opposed to operating on model instances.
  261. </p>
  262. <ul class="small">
  263. <li><a href="#RelationalModel-setup">setup</a></li>
  264. <li><a href="#RelationalModel-build">build</a></li>
  265. <li><a href="#RelationalModel-findOrCreate">findOrCreate</a></li>
  266. <li><a href="#RelationalModel-find">find</a></li>
  267. <li><a href="#RelationalModel-findModel">findModel</a></li>
  268. </ul>
  269. <h3 id="RelationalModel-properties">
  270. Properties
  271. </h3>
  272. <h4 class="code" id="RelationalModel-relations">
  273. relations<code>relation[]</code>
  274. </h4>
  275. <p>
  276. A <strong>Backbone.RelationalModel</strong> may contain an array of relation definitions. Each relation supports a number of
  277. options, of which <a href="#relations-relatedModel"><q>relatedModel</q></a>, <a href="#relations-key"><q>key</q></a> and
  278. <a href="#relations-type"><q>type</q></a> are mandatory. A relation could look like the following:
  279. </p>
  280. <pre class="language-javascript"><code id="example-zoo" class="language-javascript runnable"><!--
  281. -->Zoo = Backbone.RelationalModel.extend({
  282. relations: [{
  283. type: Backbone.HasMany,
  284. key: 'animals',
  285. relatedModel: 'Animal',
  286. collectionType: 'AnimalCollection',
  287. reverseRelation: {
  288. key: 'livesIn',
  289. includeInJSON: 'id'
  290. // 'relatedModel' is automatically set to 'Zoo'; the 'relationType' to 'HasOne'.
  291. }
  292. }]
  293. });
  294. Animal = Backbone.RelationalModel.extend({
  295. urlRoot: '/animal/'
  296. });
  297. AnimalCollection = Backbone.Collection.extend({
  298. model: Animal
  299. });
  300. // We've now created a fully managed relation. When you add or remove model from `zoo.animals`,
  301. // or update `animal.livesIn`, the other side of the relation will automatically be updated.
  302. var artis = new Zoo( { name: 'Artis' } );
  303. var lion = new Animal( { species: 'Lion', livesIn: artis } );
  304. // `animals` in `artis` now contains `lion`
  305. alert( artis.get( 'animals' ).pluck( 'species' ) );
  306. </code></pre>
  307. <pre class="language-javascript nomargin"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
  308. -->var amersfoort = new Zoo( { name: 'Dierenpark Amersfoort', animals: [ lion ] } );
  309. // `lion` now livesIn `amersfoort`, and `animals` in `artis` no longer contains `lion`
  310. alert( lion.get( 'livesIn' ).get( 'name' ) + ', ' + artis.get( 'animals' ).length );
  311. </code></pre>
  312. <section id="relations-key">
  313. <h4 class="code">
  314. key<code>relation.key</code>
  315. </h4>
  316. <p>
  317. Required. A string that references an attribute name on <a href="#relations-relatedModel"><q>relatedModel</q></a>.
  318. </p>
  319. <h4 class="code" id="relations-relatedModel">
  320. relatedModel<code>relation.relatedModel</code>
  321. </h4>
  322. <p>
  323. Required. A string that can be resolved to an object on the global scope, or a reference to a
  324. <strong>Backbone.RelationalModel</strong>. Also see <a href="#Store-addModelScope"><q>addModelScope</q></a>.
  325. </p>
  326. </section>
  327. <section id="relations-type">
  328. <h4 class="code">
  329. type<code>relation.type</code>
  330. </h4>
  331. <p>
  332. Required. A string that references a <a href="#Relation"><q>Backbone.Relation</q></a> type by name ("HasOne" or "HasMany"),
  333. or a direct reference to a relation type.
  334. </p>
  335. <p>
  336. You can model a one-to-one or a many-to-one relationship by declaring <q>type</q> as the string "HasOne", or by
  337. directly referencing <a href="#Relation-HasOne"><q>Backbone.HasOne</q></a>. A HasOne relation contains a single
  338. <strong>Backbone.RelationalModel</strong>. The default <q>reverseRelation.type</q> for a "HasOne" relation is
  339. "HasMany". This can be set to "HasOne" instead, to create a one-to-one relation.
  340. </p>
  341. <p>
  342. You can model a one-to-many relationship by declaring <q>type</q> as the string "HasMany", or by directly
  343. referencing <a href="#Relation-HasMany"><q>Backbone.HasMany</q></a>. A HasMany relation contains a Backbone.Collection,
  344. containing zero or more <strong>Backbone.RelationalModel</strong>s. The default <q>reverseRelation.type</q>
  345. for a HasMany relation is HasOne; this is the only option here, since many-to-many is not supported directly.
  346. </p>
  347. <p>
  348. It is possible model a many-to-many relationship using two <a href="#Relation-HasMany"><q>Backbone.HasMany</q></a>
  349. relations, with a link model in between:
  350. </p>
  351. </section>
  352. <pre class="language-javascript"><code class="language-javascript" id="example-job"><!--
  353. -->Person = Backbone.RelationalModel.extend({
  354. relations: [{
  355. type: 'HasMany',
  356. key: 'jobs',
  357. relatedModel: 'Job',
  358. reverseRelation: {
  359. key: 'person'
  360. }
  361. }]
  362. });
  363. // A link object between 'Person' and 'Company'
  364. Job = Backbone.RelationalModel.extend({
  365. defaults: {
  366. 'startDate': null,
  367. 'endDate': null
  368. }
  369. })
  370. Company = Backbone.RelationalModel.extend({
  371. relations: [{
  372. type: 'HasMany',
  373. key: 'employees',
  374. relatedModel: 'Job',
  375. reverseRelation: {
  376. key: 'company'
  377. }
  378. }]
  379. });
  380. </code></pre>
  381. <section id="relations-includeInJSON">
  382. <h4 class="code">
  383. includeInJSON<code>relation.includeInJSON</code>
  384. </h4>
  385. <p>
  386. A boolean, a string referencing one of the model's attributes, or an array of strings referencing model
  387. attributes. Default: <q>true</q>.
  388. </p>
  389. <p>
  390. Determines how the contents of a relation will be serialized following a call to the
  391. <a href="#RelationalModel-toJSON"><q>toJSON</q></a> method. If you specify a:
  392. </p>
  393. <ul>
  394. <li>
  395. <strong>Boolean</strong>: a value of true serializes the full set of attributes on the related model(s).
  396. Set to false to exclude the relation completely.
  397. </li>
  398. <li>
  399. <strong>String</strong>: include a single attribute from the related model(s). For example, 'name', or
  400. <q>Backbone.Model.prototype.idAttribute</q> to include ids.
  401. </li>
  402. <li>
  403. <strong>String[]</strong>: includes the specified attributes from the related model(s).
  404. </li>
  405. </ul>
  406. <p>
  407. Specifying <q>true</q> will cascade, meaning the relations of nested model will get serialized as well,
  408. until either a different value is found for <q>includeInJSON</q> or we encounter a model that has already
  409. been serialized.
  410. </p>
  411. </section>
  412. <section id="relations-autoFetch">
  413. <h4 class="code">
  414. autoFetch<code>relation.autoFetch</code>
  415. </h4>
  416. <p>
  417. A boolean or an object. Default: <q>false</q>.
  418. </p>
  419. <p>
  420. If this property is set to <q>true</q>, when a model is instantiated the related model is
  421. automatically fetched using <a href="#RelationalModel-getAsync"><q>getAsync</q></a>. The
  422. value of the property can also be an object. In that case the object is passed to
  423. <a href="#RelationalModel-getAsync"><q>getAsync</q></a> as the options parameter.
  424. </p>
  425. <p>
  426. Note that <q>autoFetch</q> operates independently from other `fetch` operations,
  427. including those that may have fetched the current model.
  428. </p>
  429. </section>
  430. <pre class="language-javascript"><code class="language-javascript"><!--
  431. -->var Shop = Backbone.RelationalModel.extend({
  432. relations: [
  433. {
  434. type: Backbone.HasMany,
  435. key: 'customers',
  436. relatedModel: 'Customer',
  437. autoFetch: true
  438. },
  439. {
  440. type: Backbone.HasOne,
  441. key: 'address',
  442. relatedModel: 'Address',
  443. autoFetch: {
  444. success: function( model, response ) {
  445. //...
  446. },
  447. error: function( model, response ) {
  448. //...
  449. }
  450. }
  451. }
  452. ]
  453. });
  454. </code></pre>
  455. <section id="relations-collectionType">
  456. <h4 class="code">
  457. collectionType<code>relation.collectionType</code>
  458. </h4>
  459. <p>
  460. A string that can be resolved to an object type on the global scope, or a reference to a
  461. <strong>Backbone.Collection</strong> type.
  462. </p>
  463. <p>
  464. Determine the type of collections used for a HasMany relation. If you define a
  465. url(models&lt;Backbone.Model[]&gt;) function on the specified collection, this enables
  466. <a href="#RelationalModel-getAsync"><q>getAsync</q></a> to fetch all missing models in one request,
  467. instead of firing a separate request for each.
  468. </p>
  469. <h4 class="code" id="relations-collectionKey">
  470. collectionKey<code>relation.collectionKey</code>
  471. </h4>
  472. <p>
  473. A string or a boolean. Default: <q>true</q>.
  474. </p>
  475. <p>
  476. Used to create a back reference from the <strong>Backbone.Collection</strong> used for a HasMany relation to the model on
  477. the other side of this relation. By default, the relation's key attribute will be used to create a reference to
  478. the RelationalModel instance from the generated collection. If you set <q>collectionKey</q> to a string,
  479. it will use that string as the reference to the RelationalModel, rather than the
  480. relation's key attribute. If you don't want this behavior at all, set <q>collectionKey</q> to <q>false</q>
  481. (or any falsy value) and this reference will not be created.
  482. </p>
  483. </section>
  484. <section id="relations-collectionOptions">
  485. <h4 class="code">
  486. collectionOptions<code>relation.collectionOptions</code>
  487. </h4>
  488. <p>
  489. An options hash, or a function that accepts an instance of a <strong>Backbone.RelationalModel</strong> and returns an options
  490. hash.
  491. </p>
  492. <p>
  493. Used to provide options for the initialization of the collection in the 'Many'-end of a HasMany relation. Can be
  494. an options hash or a function that should take the instance in the 'One'-end of the 'HasMany' relation and return
  495. an options hash.
  496. </p>
  497. </section>
  498. <section id="relations-createModels">
  499. <h4 class="code">
  500. createModels<code>relation.createModels</code>
  501. </h4>
  502. <p>
  503. A boolean. Default: <q>true</q>.
  504. </p>
  505. <p>
  506. Specifies whether models will be created from nested objects or not.
  507. </p>
  508. </section>
  509. <section id="relations-keySource">
  510. <h4 class="code">
  511. keySource<code>relation.keySource</code>
  512. </h4>
  513. <p>
  514. A string that references an attribute to deserialize data for <a href="#relations-relatedModel"><q>relatedModel</q></a> from.
  515. </p>
  516. <p>
  517. Used to override key when determining what data to use when (de)serializing a relation, since the data backing
  518. your relations may use different naming conventions. For example, a Rails backend may provide the keys suffixed
  519. with <q>_id</q> or <q>_ids</q>. The behavior for <q>keySource</q> corresponds to the following rules:
  520. </p>
  521. <p>
  522. When a relation is instantiated, the contents of the <q>keySource</q> are used as its initial data. The
  523. application uses the regular key attribute to interface with the relation and the models in it; the
  524. <q>keySource</q> is not available as an attribute for the model. So you may be provided with data containing
  525. <q>animal_ids</q>, while you want to access this relation as <q>zoo.get('animals')</q>.
  526. </p>
  527. <p class="warning">
  528. Note that setting <q>keySource</q> will set <a href="#relations-keyDestination"><q>keyDestination</q></a>
  529. to the same value, if it isn't specified itself.
  530. This means that when saving zoo, the animals attribute will be serialized back into the <q>animal_ids</q> key.
  531. </p>
  532. <p class="warning">
  533. WARNING: when using a keySource, you should not use that attribute name for other purposes.
  534. </p>
  535. </section>
  536. <section id="relations-keyDestination">
  537. <h4 class="code">
  538. keyDestination<code>relation.keyDestination</code>
  539. </h4>
  540. <p>
  541. A string that references an attribute to serialize <a href="#relations-relatedModel"><q>relatedModel</q></a> into.
  542. </p>
  543. <p>
  544. Used to override key (and <a href="#relations-keySource"><q>keySource</q></a>) when determining what attribute to be
  545. written into when serializing a relation, since the server backing your relations may use different naming
  546. conventions. For example, a Rails backend may expect the keys to be suffixed with _attributes for nested
  547. attributes.
  548. </p>
  549. <p>
  550. When calling <a href="#RelationalModel-toJSON"><q>toJSON</q></a> on a model (either via
  551. <strong>Backbone.Sync</strong>, or directly), the data in the key attribute is transformed and assigned to the
  552. <q>keyDestination</q>.
  553. </p>
  554. <p>
  555. So you may want a relation to be serialized into the animals_attributes key, while you want to access this
  556. relation as <q>zoo.get( 'animals' );</q>.
  557. </p>
  558. <p class="warning">
  559. WARNING: when using a <q>keyDestination</q>, you should not use that attribute name for other purposes.
  560. </p>
  561. </section>
  562. <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
  563. -->var FarmAnimal = Animal.extend();
  564. // This `Farm` is confused, like legacy stuff can be. It wants its data back on a completely
  565. // different key than it supplies it on. We want to use a different one in our app as well.
  566. var Farm = Backbone.RelationalModel.extend({
  567. relations: [{
  568. type: Backbone.HasMany,
  569. key: 'animals',
  570. keySource: 'livestock',
  571. keyDestination: 'pets',
  572. relatedModel: FarmAnimal,
  573. reverseRelation: {
  574. key: 'farm',
  575. includeInJSON: 'name'
  576. }
  577. }]
  578. });
  579. // Create a `Farm`; parse `species`, add to `animals`, output goes to `pets`.
  580. var farm = new Farm( { name: 'Old MacDonald', livestock: [ { species: 'Sheep' } ] } );
  581. farm.get( 'animals' ).add( { species: 'Cow' } );
  582. alert( JSON.stringify( farm.toJSON(), null, 4 ) );
  583. </code></pre>
  584. <section id="relations-parse">
  585. <h4 class="code">
  586. parse<code>relation.parse</code>
  587. </h4>
  588. <p>
  589. A boolean. Default: <q>false</q>.
  590. </p>
  591. <p>
  592. If you have a relation where the models should be parsed when data is being set, specify `parse: true`.
  593. </p>
  594. </section>
  595. <section id="relations-reverseRelation">
  596. <h4 class="code">
  597. reverseRelation<code>relation.reverseRelation</code>
  598. </h4>
  599. <p>
  600. An object specifying the relation pointing back to this model from <a href="#relations-relatedModel"><q>relatedModel</q></a>.
  601. </p>
  602. <p>
  603. If the relation should be bidirectional, specify the details for the reverse relation here. It's only mandatory
  604. to supply a <a href="#relations-key"><q>key</q></a>; <a href="#relations-relatedModel"><q>relatedModel</q></a> is automatically
  605. set. The default type for a <q>reverseRelation</q> is HasMany for a
  606. HasOne relation (which can be overridden to HasOne in order to create a one-to-one relation), and HasOne for a
  607. HasMany relation. In this case, you cannot create a <q>reverseRelation</q> with
  608. type HasMany as well; please see Many-to-many relations on how to model these type of relations.
  609. </p>
  610. <p class="warning">
  611. Note that if you define a relation (plus a reverseRelation) on a model, but don't actually create an instance
  612. of that model, it is possible <q>initializeRelations</q> will never get called, and the reverseRelation
  613. will not be initialized. This can happen when <q>extend</q> has been overridden, or redefined as in CoffeeScript.
  614. See <a href="#RelationalModel-setup">setup</a>.
  615. </p>
  616. </section>
  617. <section id="RelationalModel-subModelTypes">
  618. <h4 class="code">
  619. subModelTypes<code>relationalModel.subModelTypes(attributes&lt;object&gt;, [options&lt;object&gt;])</code>
  620. </h4>
  621. <p>
  622. An object. Default: <q>{}</q>.
  623. </p>
  624. <p>
  625. A mapping that defines what submodels exist for the model (the superModel) on which
  626. <q>subModelTypes</q> is defined. The keys are used to match the
  627. <a href="#RelationalModel-subModelTypeAttribute"><q>subModelTypeAttribute</q></a> when deserializing, and the values
  628. determine what type of submodel should be created for a key. When building model instances from data, we need to
  629. determine what kind of object we're dealing with in order to create instances of the right subModel type. This
  630. is done by finding the model for which the key is equal to the value of the
  631. <a href="#RelationalModel-subModelTypeAttribute"><q>subModelTypeAttribute</q></a> attribute on the passed in data.
  632. </p>
  633. <p>
  634. Each subModel is considered to be a proper submodel of its superclass (the model type you're extending), with a
  635. shared id pool. This means that when looking for an object of the supermodel's type, objects of a submodel's type
  636. can be returned as well, as long as the id matches. In effect, any relations pointing to the supermodel will look
  637. for instances of its submodels as well.
  638. </p>
  639. <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
  640. -->Mammal = Animal.extend({
  641. subModelTypes: {
  642. 'primate': 'Primate',
  643. 'carnivore': 'Carnivore'
  644. }
  645. });
  646. Primate = Mammal.extend();
  647. Carnivore = Mammal.extend();
  648. MammalCollection = AnimalCollection.extend({
  649. model: Mammal
  650. });
  651. // Create a collection that contains a 'Primate' and a 'Carnivore'.
  652. var mammals = new MammalCollection([
  653. { id: 3, species: 'chimp', type: 'primate' },
  654. { id: 5, species: 'panther', type: 'carnivore' }
  655. ]);
  656. var chimp = mammals.get( 3 );
  657. alert( 'chimp is an animal? ' + ( chimp instanceof Animal ) + '\n' +
  658. 'chimp is a carnivore? ' + ( chimp instanceof Carnivore ) + '\n' +
  659. 'chimp is a primate? ' + ( chimp instanceof Primate ) );
  660. </code></pre>
  661. <p>
  662. Suppose that we have an Mammal model and a Primate model extending Mammal. If we have a Primate object with id 3,
  663. this object will be returned when we have a relation pointing to a Mammal with id 3, as Primate is regarded a
  664. specific kind of Mammal; it's just a Mammal with possibly some primate-specific properties or methods.
  665. </p>
  666. <p class="warning">
  667. Note that this means that there cannot be any overlap in ids between instances of Mammal and Primate, as the
  668. Primate with id 3 will be the Mammal with id 3.
  669. </p>
  670. </section>
  671. <section id="RelationalModel-subModelTypeAttribute">
  672. <h4 class="code">
  673. subModelTypeAttribute<code>relationalModel.subModelTypeAttribute</code>
  674. </h4>
  675. <p>
  676. A string. Default: <q>type</q>.
  677. </p>
  678. <p>
  679. The <q>subModelTypeAttribute</q> is a references an attribute on the data
  680. used to instantiate <a href="#relations-relatedModel"><q>relatedModel</q></a>. The attribute that will be checked to
  681. determine the type of model that should be built when a raw object of attributes is set as the related value,
  682. and if the <a href="#relations-relatedModel"><q>relatedModel</q></a> has one or more submodels.
  683. </p>
  684. </section>
  685. <h3 id="RelationalModel-instance-methods">
  686. Instance methods
  687. </h3>
  688. <section id="RelationalModel-getAsync">
  689. <h4 class="code">
  690. getAsync<code>relationalModel.getAsync(attr&lt;string&gt;, [options&lt;object&gt;], [refresh&lt;boolean&gt;])</code>
  691. </h4>
  692. <p>
  693. Returns: <q>jQuery.Deferred</q> A <a href="http://api.jquery.com/category/deferred-object/">jQuery promise</a>
  694. </p>
  695. <p>
  696. Get an attribute's value asynchronously. If available, the local value will be returned.
  697. If <q>attr</q> is a relation and one or more of its models are not available, they will be fetched.
  698. </p>
  699. <p>
  700. This can be used specifically for lazy-loading scenarios.
  701. Only models are referenced in the attributes but have not been found/created yet are fetched.
  702. Setting <q>options.refresh</q> to true will fetch all model(s) from the server.
  703. In that case, any model that already exists will be updated with the retrieved data.
  704. The <q>options</q> object specifies options to be passed to <a href="http://backbonejs.org/#Sync">Backbone.Sync</a>.
  705. </p>
  706. <p>
  707. By default, a separate request will be fired for each model that is to be fetched from the server (if `key` references a collection).
  708. However, if your server/API supports it, you can fetch the set of models in one request by specifying a
  709. collectionType for the relation you call getAsync on. The <a href="#relations-collectionType"><q>collectionType</q></a>
  710. should have an overridden <a href="http://backbonejs.org/#Collection-url"><q>url</q></a>
  711. method that allows it to construct a url for an array of models. See <a href="#example-person">this example</a>
  712. or <a href="https://github.com/PaulUithol/backbone-tastypie">Backbone-tastypie</a> for an example.
  713. </p>
  714. </section>
  715. <section id="RelationalModel-getIdsToFetch">
  716. <h4 class="code">
  717. getRelations<code>relationModel.getIdsToFetch(attr&lt;string|Backbone.Relation&gt;, )</code>
  718. </h4>
  719. <p>
  720. Returns: <q>Array</q> A list of the ids that will be fetched when calling <q>getAsync</q>.
  721. </p>
  722. </section>
  723. <section id="RelationalModel-getRelation">
  724. <h4 class="code">
  725. getRelation<code>relationModel.getRelation(attr&lt;string&gt;)</code>
  726. </h4>
  727. <p>
  728. Returns: <q>Backbone.Relation</q> A single initialized relation on the model.
  729. </p>
  730. </section>
  731. <section id="RelationalModel-getRelations">
  732. <h4 class="code">
  733. getRelations<code>relationModel.getRelations()</code>
  734. </h4>
  735. <p>
  736. Returns: <q>Backbone.Relation[]</q> The set of initialized relations on the model.
  737. </p>
  738. </section>
  739. <section id="RelationalModel-set">
  740. <h4 class="code">
  741. set<code>set(key&lt;string&gt;, value, [options&lt;object&gt;]) <strong>or</strong> set(attributes&lt;object&gt;, [options&lt;object&gt;])</code>
  742. </h4>
  743. <p>
  744. Returns: <q>Backbone.RelationalModel</q> The model instance.
  745. </p>
  746. <p>
  747. The <q>set</q> method is overridden so that setting a value on an "relational" attribute will update that relation.
  748. This is especially important to keep in mind for <q>HasMany</q> relations (which are backed by a <q>Backbone.Collection</q>).
  749. For these, calling <q>set</q> can be thought of as being equivalent to calling <q>update</q> on the collection itself,
  750. including how the options are handled.
  751. </p>
  752. <p>
  753. Additional <q>options</q> for a <q>HasMany</q> relation:
  754. </p>
  755. <dl>
  756. <dt><q>add</q></dt>
  757. <dd>Default: <q>true</q>. If true, models specified in the arguments but not yet present in the relation will be added to the relation.</dd>
  758. <dt><q>merge</q></dt>
  759. <dd>Default: <q>true</q>. If true, existing models will be updated with the given attributes.</dd>
  760. <dt><q>remove</q></dt>
  761. <dd>Default: <q>true</q>. If true, models present in the relation but not specified in the arguments will be removed.</dd>
  762. </dl>
  763. </section>
  764. <section id="RelationalModel-toJSON">
  765. <h4 class="code">
  766. toJSON<code>relationModel.toJSON(name&lt;string&gt;)</code>
  767. </h4>
  768. <p>
  769. Returns: <q>Object</q> The JSON representation of the model.
  770. See <a href="http://backbonejs.org/#Model-toJSON">Backbone.Model.toJSON</a>.
  771. </p>
  772. <p>
  773. The regular <q>toJSON</q> function has been overridden and modified to serialize (nested) relations
  774. according to their <a href="#relations-includeInJSON"><q>includeInJSON</q></a>, <a href="#relations-keySource"><q>keySource</q></a>,
  775. and <a href="#relations-keyDestination"><q>keyDestination</q></a> options.
  776. </p>
  777. </section>
  778. <h3 id="RelationalModel-static-methods">
  779. Static methods
  780. </h3>
  781. <section id="RelationalModel-setup">
  782. <h4 class="code">
  783. setup<code>relationModel.setup()</code>
  784. </h4>
  785. <p>
  786. Returns: <q>Backbone.RelationalModel.constuctor</q> The type.
  787. </p>
  788. <p>
  789. Initialize the relations and submodels for the model type. Normally, this happens automatically, but it doesn't if
  790. you're using CoffeeScript and using the syntax <q>class MyModel extends Backbone.RelationalModel</q> instead of
  791. the JavaScript equivalent of <q>MyModel = Backbone.RelationalModel.extend()</q>.
  792. </p>
  793. <p>
  794. This has advantages in CoffeeScript, but it also means that <q>Backbone.Model.extend</q> will not get called.
  795. Instead, CoffeeScript generates piece of code that would normally achieve the same. However, <q>extend</q> is also
  796. the method that Backbone-relational overrides to set up relations as you're defining your <q>Backbone.RelationalModel</q> subclass.
  797. </p>
  798. <p>
  799. In this case, you should call <q>setup</q> manually after defining your subclass CoffeeScript-style. For example:
  800. </p>
  801. <p class="warning">
  802. Note: this is a static method. It operates on the model type itself, not on an instance of it.
  803. </p>
  804. </section>
  805. <pre class="language-javascript"><code class="language-javascript"><!--
  806. -->class Animal extends Backbone.RelationalModel
  807. urlRoot: "/animal"
  808. class Mammal extends Animal
  809. subModelTypes:
  810. "primate": "Primate"
  811. "carnivore": "Carnivore"
  812. relations: [
  813. # More relations
  814. ]
  815. Mammal.setup()
  816. class Primate extends Mammal
  817. class Carnivore extends Mammal
  818. chimp = Mammal.build( { id: 3, species: "chimp", type: "primate" } )
  819. </code></pre>
  820. <section id="RelationalModel-build">
  821. <h4 class="code">
  822. build<code>relationalModel.build(attributes&lt;object&gt;, [options&lt;object&gt;])</code>
  823. </h4>
  824. <p>
  825. Returns: <q>Backbone.RelationalModel</q> A model instance.
  826. </p>
  827. <p>
  828. Create an instance of a model, taking into account what submodels have been defined.
  829. </p>
  830. <p class="warning">
  831. Note: this is a static method. It operates on the model type itself, not on an instance.
  832. </p>
  833. </section>
  834. <section id="RelationalModel-findOrCreate">
  835. <h4 class="code">
  836. findOrCreate
  837. <code>relationalModel.findOrCreate(attributes&lt;string|number|object&gt;, [options&lt;object&gt;])</code>
  838. </h4>
  839. <p>
  840. Returns: <q>Backbone.RelationalModel</q> A model instance.
  841. </p>
  842. <p>
  843. Search for a model instance in the <a href="#Store">Backbone.Relational.store</a>, and return the model if found.
  844. A new model will be created if no model is found, <q>attributes</q> is an object, and <q>options.create</q> is <q>true</q>.
  845. </p>
  846. <p>
  847. Accepted <q>options</q>:
  848. </p>
  849. <dl>
  850. <dt><q>create</q></dt>
  851. <dd>Default: <q>true</q>. If true, a new model will be created if an instance matching <q>attributes</q> isn't found in the store.</dd>
  852. <dt><q>merge</q></dt>
  853. <dd>Default: <q>true</q>. If true, a found model will be updated with <q>attributes</q> (if <q>attributes</q> is an <q>object</q>).</dd>
  854. <dt><q>parse</q></dt>
  855. <dd>Default: <q>false</q>. If true, <q>attributes</q> will be parsed first. Please note this will cause <q>Model.parse</q> to be called
  856. as a function (<q>this</q> will not point to a model), instead of as a method.</dd>
  857. </dl>
  858. <p class="warning">
  859. Note: this is a static method. It operates on the model type itself, not on an instance of it.
  860. </p>
  861. </section>
  862. <section id="RelationalModel-find">
  863. <h4 class="code">
  864. find
  865. <code>relationalModel.find(attributes&lt;string|number|object&gt;, [options&lt;object&gt;])</code>
  866. </h4>
  867. <p>
  868. Returns: <q>Backbone.RelationalModel</q> A model instance.
  869. </p>
  870. <p>
  871. A shortcut for <a href="#RelationalModel-findOrCreate"><q>findOrCreate</q></a> that uses <q>create: false</q>.
  872. Accepts the same options as <q>findOrCreate</q> (except for <q>create</q>).
  873. </p>
  874. <p class="warning">
  875. Note: this is a static method. It operates on the model type itself, not on an instance of it.
  876. </p>
  877. </section>
  878. <section id="RelationalModel-findModel">
  879. <h4 class="code">
  880. findModel
  881. <code>relationalModel.findModel(attributes&lt;string|number|object&gt;)</code>
  882. </h4>
  883. <p>
  884. Returns: <q>Backbone.RelationalModel</q> A model instance.
  885. </p>
  886. <p>
  887. A hook to override the matching when updating (or creating) a model.
  888. The default implementation is to look up the model by id in the store:
  889. <q>return Backbone.Relational.store.find( this, attributes );</q>
  890. </p>
  891. <p>
  892. Custom behavior is useful in cases where (a collection of) nested data gets saved to the server.
  893. Consider saving the following model:
  894. </p>
  895. <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
  896. -->var zoo = new Zoo( { id: 1, name: 'Artis', animals: [
  897. { species: 'Giraffe' },
  898. { species: 'Camel' }
  899. ] } );
  900. alert( JSON.stringify( zoo.toJSON(), null, 4 ) );
  901. </code></pre>
  902. <p>
  903. Normally, whatever you use as server-side logic will respond by creating two animals, and assigning them
  904. an id. The response will be used by Backbone-relational to update existing models.
  905. However, updating a model starts by looking up the local model with the same id; and in this case,
  906. Backbone-relational does not know which local models corresponds to which created animal with an id.
  907. A simple fix in this case would be to add a fallback option for the matching by using the animal's
  908. species. Do note you'd want to use a more robust method usually, such as using a new model's <q>cid</q>.
  909. </p>
  910. <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
  911. -->Zoo.findModel = function( attributes ) {
  912. // Try to find an instance of 'this' model type in the store
  913. var model = Backbone.Relational.store.find( this, attributes );
  914. if ( !model && _.isObject( attributes ) ) {
  915. var coll = Backbone.Relational.store.getCollection( this );
  916. model = coll.find( function( m ) {
  917. return m.species === attributes.species;
  918. });
  919. }
  920. return model;
  921. };
  922. </code></pre>
  923. <p class="warning">
  924. Note: this is a static method. It operates on the model type itself, not on an instance of it.
  925. </p>
  926. </section>
  927. <section id="RelationalModel-events">
  928. <h4>
  929. Catalog of Events
  930. </h4>
  931. <p>
  932. Backbone-relational makes a couple of additional events available to you, on top of the events already found in Backbone.
  933. </p>
  934. <ul class="small">
  935. <li>
  936. An <strong>"add"</strong> event is triggered on addition to a HasMany relation. Bind to:<br/>
  937. <q>add:&lt;key&gt;</q> &rarr;<code>function(addedModel&lt;Backbone.Model&gt;, related&lt;Backbone.Collection&gt;)</code>
  938. </li>
  939. <li>
  940. A <strong>"remove"</strong> event is triggered on removal from a HasMany relation. Bind to:<br/>
  941. <q>remove:&lt;key&gt;</q> &rarr;<code>function(removedModel&lt;Backbone.Model&gt;, related&lt;Backbone.Collection&gt;)</code>
  942. </li>
  943. <li>
  944. A <strong>"change"</strong> event is triggered on changes to the contents of both HasOne and HasMany relations. Bind to:<br/>
  945. <q>change:&lt;key&gt;</q> &rarr;<code>function(model&lt;Backbone.Model&gt;, related&lt;Backbone.Model|Backbone.Collection&gt;)</code>
  946. </li>
  947. </ul>
  948. </section>
  949. </section>
  950. <section id="Relation">
  951. <h2 >Backbone.Relation</h2>
  952. <p>
  953. Each <a href="#RelationalModel-relations">relation</a> definition on a model is used to create in instance of a <q>Backbone.Relation</q>; either
  954. a <q>Backbone.HasOne</q> or a <q>Backbone.HasMany</q>.
  955. </p>
  956. <h4 class="code" id="Relation-HasOne">
  957. Backbone.HasOne
  958. </h4>
  959. <p>
  960. Defines a <strong>HasOne</strong> relation. When defining a <a href="#relations-reverseRelation">reverseRelation</a>, the default type
  961. will be <strong>HasMany</strong>. However, this can also be set to <strong>HasOne</strong> to define a one-to-one relation.
  962. </p>
  963. <h4 class="code" id="Relation-HasMany">
  964. Backbone.HasMany
  965. </h4>
  966. <p>
  967. Defines a <strong>HasMany</strong> relation. When defining a <a href="#relations-reverseRelation">reverseRelation</a>, the type
  968. will be <strong>HasOne</strong>.
  969. </p>
  970. </section>
  971. <section id="Store">
  972. <h2 >Backbone.Store</h2>
  973. <p>
  974. <strong>Backbone.Store</strong> is a global model cache. Per application, one instance is created (much like <q>Backbone.History</q>),
  975. which is accessible as <q>Backbone.Relational.store</q>.
  976. </p>
  977. <h4 class="code" id="Store-addModelScope">
  978. addModelScope<code>Backbone.Relational.store.addModelScope(scope&lt;object&gt;)</code>
  979. </h4>
  980. <p>
  981. Add a namespace on which models and collections are defined. This is especially useful when working in an
  982. environment without a shared global scope (like <q>window</q> is in a browser), where you'll need to tell
  983. the <q>store</q> where your models are defined, so it can resolve them to create and maintain relations.
  984. </p>
  985. <h4 class="code" id="Store-removeModelScope">
  986. removeModelScope<code>Backbone.Relational.store.removeModelScope()</code>
  987. </h4>
  988. <p>
  989. Remove a scope. This allows you to remove a scope you added previously, or to remove the default 'global'
  990. scope (<q>window</q> in the browser) scope to prevent Backbone-relational from resolving objects on it.
  991. </p>
  992. <h4 class="code" id="Store-reset">
  993. reset<code>Backbone.Relational.store.reset()</code>
  994. </h4>
  995. <p>
  996. Reset the <q>store</q> to its original state. This will disable relations for all models created up to this point,
  997. remove added model scopes, and removed all internal store collections.
  998. </p>
  999. <h4 class="code" id="Store-unregister">
  1000. unregister<code>Backbone.Relational.store.unregister(type&lt;Backbone.RelationalModel|Backbone.RelationalModel.constructor|Backbone.Collection&gt;)</code>
  1001. </h4>
  1002. <p>
  1003. Unregister a single model or a collection. Unregistering a model will remove a model from any relations it's involved in.
  1004. Internally, unregister is called when a model has been destroyed. It can also be called explicitly to on models
  1005. you don't want Backbone-relational to consider for relations anymore, for example to free up models used as (temporary) search results.
  1006. </p>
  1007. </section>
  1008. <section id="examples">
  1009. <h2 >Examples</h2>
  1010. <p>
  1011. <a href="http://antoviaque.org/docs/tutorials/backbone-relational-tutorial/">A tutorial by antoviaque</a>,
  1012. and the <a href="https://github.com/antoviaque/backbone-relational-tutorial">accompanying git repository</a>.
  1013. </p>
  1014. <p>
  1015. A basic working example to get you started:
  1016. </p>
  1017. <pre class="language-javascript"><code id="example-person-run1" class="language-javascript runnable" data-setup="#example-person"><!--
  1018. -->var paul = new Person({
  1019. id: 'person-1',
  1020. name: 'Paul',
  1021. user: { id: 'user-1', login: 'dude', email: 'me@gmail.com' }
  1022. });
  1023. // A User object is automatically created from the JSON; so 'login' returns 'dude'.
  1024. paul.get('user').get('login');
  1025. var ourHouse = new House({
  1026. id: 'house-1',
  1027. location: 'in the middle of the street',
  1028. occupants: ['person-1', 'person-2', 'person-5']
  1029. });
  1030. // 'ourHouse.occupants' is turned into a Backbone.Collection of Persons.
  1031. // The first person in 'ourHouse.occupants' will point to 'paul'.
  1032. ourHouse.get('occupants').at(0); // === paul
  1033. // If a collection is created from a HasMany relation, it contains a reference
  1034. // back to the originator of the relation
  1035. ourHouse.get('occupants').livesIn; // === ourHouse
  1036. // The `occupants` relation on 'House' has been defined as a HasMany, with a reverse relation
  1037. // to `livesIn` on 'Person'. So, 'paul.livesIn' will automatically point back to 'ourHouse'.
  1038. paul.get('livesIn'); // === ourHouse
  1039. // You can control which relations get serialized to JSON, using the 'includeInJSON'
  1040. // property on a Relation. Also, each object will only get serialized once to prevent loops.
  1041. alert( JSON.stringify( paul.get('user').toJSON(), null, '\t' ) );
  1042. </code></pre>
  1043. <pre class="language-javascript nomargin"><code id="example-person-run2" class="language-javascript runnable" data-setup="#example-person-run1"><!--
  1044. -->// Load occupants 'person-2' and 'person-5', which don't exist yet, from the server
  1045. ourHouse.getAsync( 'occupants' );
  1046. // Use the `add` and `remove` events to listen for additions/removals on a HasMany relation.
  1047. // Here, we listen for changes to `ourHouse.occupants`.
  1048. ourHouse
  1049. .on( 'add:occupants', function( model, coll ) {
  1050. console.log( 'add %o', model );
  1051. // Do something. Create a View?
  1052. })
  1053. .on( 'remove:occupants', function( model, coll ) {
  1054. console.log( 'remove %o', model );
  1055. // Do somehting. Destroy a View?
  1056. });
  1057. // Use the 'update' event to listen for changes on a HasOne relation (like 'Person.livesIn').
  1058. paul.on( 'change:livesIn', function( model, attr ) {
  1059. console.log( 'change `livesIn` to %o', attr );
  1060. });
  1061. // Modifying either side of a bi-directional relation updates the other side automatically.
  1062. // Take `paul` out or `ourHouse`; this triggers `remove:occupants` on `ourHouse`,
  1063. // and `change:livesIn` on `paul`
  1064. ourHouse.get( 'occupants' ).remove( paul );
  1065. alert( 'paul.livesIn=' + paul.get( 'livesIn' ) );
  1066. </code></pre>
  1067. <pre class="language-javascript nomargin"><code id="example-person-run3" class="language-javascript runnable" data-setup="#example-person-run2"><!--
  1068. -->// Move into `theirHouse`; triggers 'add:occupants' on ourHouse, and 'change:livesIn' on paul
  1069. theirHouse = new House( { id: 'house-2' } );
  1070. paul.set( { 'livesIn': theirHouse } );
  1071. alert( 'theirHouse.occupants=' + theirHouse.get( 'occupants' ).pluck( 'name' ) );
  1072. </code></pre>
  1073. <p>This is achieved using the following relations and models:</p>
  1074. <pre class="language-javascript"><code class="language-javascript" id="example-person"><!--
  1075. -->House = Backbone.RelationalModel.extend({
  1076. // The 'relations' property, on the House's prototype. Initialized separately for each
  1077. // instance of House. Each relation must define (as a minimum) the 'type', 'key' and
  1078. // 'relatedModel'. Options include 'includeInJSON', 'createModels' and 'reverseRelation'.
  1079. relations: [
  1080. {
  1081. type: Backbone.HasMany, // Use the type, or the string 'HasOne' or 'HasMany'.
  1082. key: 'occupants',
  1083. relatedModel: 'Person',
  1084. includeInJSON: Backbone.Model.prototype.idAttribute,
  1085. collectionType: 'PersonCollection',
  1086. reverseRelation: {
  1087. key: 'livesIn'
  1088. }
  1089. }
  1090. ]
  1091. });
  1092. Person = Backbone.RelationalModel.extend({
  1093. relations: [
  1094. { // Create a (recursive) one-to-one relationship
  1095. type: Backbone.HasOne,
  1096. key: 'user',
  1097. relatedModel: 'User',
  1098. reverseRelation: {
  1099. type: Backbone.HasOne,
  1100. key: 'person'
  1101. }
  1102. }
  1103. ],
  1104. initialize: function() {
  1105. // do whatever you want :)
  1106. }
  1107. });
  1108. PersonCollection = Backbone.Collection.extend({
  1109. url: function( models ) {
  1110. // Logic to create a url for the whole collection, or a set of models.
  1111. // See the tests, or Backbone-tastypie, for an example.
  1112. return '/person/' + ( models ? 'set/' + _.pluck( models, 'id' ).join(';') + '/' : '' );
  1113. }
  1114. });
  1115. User = Backbone.RelationalModel.extend();
  1116. </code></pre>
  1117. </section>
  1118. <section id="change-log">
  1119. <h2>Change Log</h2>
  1120. <h4>Master
  1121. <small>
  1122. <span class="date">(future)</span> &ndash;
  1123. <a href="https://github.com/PaulUithol/Backbone-relational/compare/0.8.8...master">diff</a> &ndash;
  1124. <a href="https://raw.github.com/PaulUithol/Backbone-relational/master/backbone-relational.js">download</a>
  1125. </small>
  1126. </h4>
  1127. <ul>
  1128. <li>
  1129. <a href="https://github.com/PaulUithol/Backbone-relational/commit/42b158d8ad5697a955a2c1e615824109dfc52234"><q>42b158d</q></a>
  1130. Add <q>getIdsToFetch</q> to <q>Backbone.RelationalModel</q>.
  1131. </li>
  1132. <li>
  1133. <a href="https://github.com/PaulUithol/Backbone-relational/commit/b7e71237d1218eec41ce69e1cf56e5eecdc96bef"><q>b7e7123</q></a>
  1134. <q>getAsync</q> (the successor of <q>fetchRelated</q>) now return a single promise, instead of an array of request objects.
  1135. </li>
  1136. <li>
  1137. <a href="https://github.com/PaulUithol/Backbone-relational/issues/467"><q>#467</q></a>:
  1138. Improve lazy loading implemenatation. Add <q>getAsync</q> to <q>Backbone.RelationalModel</q>, which always
  1139. return a single promise that resolves with the attribute's conten…

Large files files are truncated, but you can click here to view the full file