/index.html
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
- <!DOCTYPE HTML>
- <html xmlns="http://www.w3.org/1999/html">
- <head>
- <meta http-equiv="content-type" content="text/html;charset=UTF-8">
- <meta http-equiv="X-UA-Compatible" content="chrome=1">
- <meta name="viewport" content="width=device-width">
- <link rel="icon" href="static/images/favicon.ico">
-
- <link href="http://fonts.googleapis.com/css?family=Arimo" rel="stylesheet" type="text/css">
- <link rel="stylesheet" type="text/css" href="static/css/style.css">
-
- <title>Backbone-relational.js</title>
- <!--[if lt IE 9]>
- <script>
- document.createElement('header');
- document.createElement('nav');
- document.createElement('section');
- document.createElement('article');
- document.createElement('aside');
- document.createElement('footer');
- document.createElement('hgroup');
- </script>
- <![endif]-->
- </head>
- <body>
- <div id="sidebar">
- <a class="toc_title" href="#">
- Backbone-relational.js <span class="version">(0.8.8)</span>
- </a>
- <ul>
- <li class="link_out"><a href="https://github.com/PaulUithol/Backbone-relational">GitHub Repository</a></li>
- </ul>
- <a class="toc_title" href="#introduction">
- Introduction
- </a>
- <a class="toc_title" href="#installation">
- Installation
- </a>
- <a class="toc_title" href="#RelationalModel">
- Backbone.RelationalModel
- </a>
- <ul>
- <li>
- <a href="#RelationalModel-relations">relations</a>
- <ul>
- <li><a href="#relations-key">key</a></li>
- <li><a href="#relations-relatedModel">relatedModel</a></li>
- <li><a href="#relations-type">type</a></li>
- <li><a href="#relations-includeInJSON">includeInJSON</a></li>
- <li><a href="#relations-autoFetch">autoFetch</a></li>
- <li><a href="#relations-collectionType">collectionType</a></li>
- <li><a href="#relations-collectionKey">collectionKey</a></li>
- <li><a href="#relations-collectionOptions">collectionOptions</a></li>
- <li><a href="#relations-createModels">createModels</a></li>
- <li><a href="#relations-keySource">keySource</a></li>
- <li><a href="#relations-keyDestination">keyDestination</a></li>
- <li><a href="#relations-parse">parse</a></li>
- <li><a href="#relations-reverseRelation">reverseRelation</a></li>
- </ul>
- </li>
- </ul>
- <ul>
- <li><a href="#RelationalModel-subModelTypes">subModelTypes</a></li>
- <li><a href="#RelationalModel-subModelTypeAttribute">subModelTypeAttribute</a></li>
- </ul>
- <ul>
- <li><a href="#RelationalModel-getAsync">getAsync</a></li>
- <li><a href="#RelationalModel-getIdsToFetch">getIdsToFetch</a></li>
- <li><a href="#RelationalModel-getRelation">getRelation</a></li>
- <li><a href="#RelationalModel-getRelations">getRelations</a></li>
- <li><a href="#RelationalModel-set">set</a></li>
- <li><a href="#RelationalModel-toJSON">toJSON</a></li>
- </ul>
- <ul>
- <li><a href="#RelationalModel-setup">setup</a></li>
- <li><a href="#RelationalModel-build">build</a></li>
- <li><a href="#RelationalModel-findOrCreate">findOrCreate</a></li>
- <li><a href="#RelationalModel-find">find</a></li>
- <li><a href="#RelationalModel-findModel">findModel</a></li>
- </ul>
- <ul>
- <li><a href="#RelationalModel-events"><strong>Catalog of Events</strong></a></li>
- </ul>
- <a class="toc_title" href="#Relation">
- Backbone.Relation
- </a>
- <ul>
- <li><a href="#Relation-HasOne">HasOne</a></li>
- <li><a href="#Relation-HasMany">HasMany</a></li>
- </ul>
- <a class="toc_title" href="#Store">
- Backbone.Store
- </a>
- <ul>
- <li><a href="#Store-addModelScope">addModelScope</a></li>
- <li><a href="#Store-removeModelScope">removeModelScope</a></li>
- <li><a href="#Store-reset">reset</a></li>
- </ul>
- <a class="toc_title" href="#examples">
- Examples
- </a>
- <a class="toc_title" href="#change-log">
- Change Log
- </a>
- <a class="toc_title" href="#under-the-hood">
- Under the Hood
- </a>
- </div>
- <div class="container">
- <section>
- <h1>
- Backbone-relational.js
- </h1>
- <p>
- When developing any medium to large-scale web application, you often get to the point where
- an action by a user can cause a number of different models to change on the client and the server.
- </p>
- <p>
- You can try to keep updating both sides of a relation manually for every action, and individually call
- <q><a href="http://backbonejs.org/#Model-save">save</a></q> or <q><a href="http://backbonejs.org/#Model-fetch">fetch</a></q>
- on each of the changed models to sync with the server, but that quickly turns into a tedious process and
- results in multiple requests.
- </p>
- <p>
- Using Backbone-relational, we can configure relationships between our models, and sync the model and all of its related models with a single
- 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>
- after setting up a model's <q><a href="#RelationalModel-relations">relations</a></q>.
- </p>
- <p>
- Backbone-relational is hosted on <a href="https://github.com/PaulUithol/Backbone-relational">GitHub</a>,
- and is available under the <a href="https://github.com/PaulUithol/Backbone-relational/blob/master/LICENSE.txt">MIT license</a>.
- </p>
- <p>
- Thanks to <a href="http://progressiveplanning.com">Progressive Planning</a> for allowing me the time to
- work on Backbone-relational!
- </p>
- </section>
- <section id="downloads">
- <h2>
- Downloads & Dependencies
- <span style="padding-left: 7px; font-size:11px; font-weight: normal;" class="interface">
- (Right-click, and use "Save As")
- </span>
- </h2>
- <table>
- <tr>
- <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>
- <td class="text"><i>~70kb. Full source, uncompressed, lots of comments.</i></td>
- </tr>
- <tr>
- <td><a class="punch" href="https://raw.github.com/PaulUithol/Backbone-relational/master/backbone-relational.js">Development Version</a></td>
- </tr>
- </table>
- <p>
- Backbone-relational depends on <a href="http://backbonejs.org/">Backbone.js</a> <small>(>= 1.0.0)</small>,
- which itself requires <a href="http://underscorejs.org">Underscore.js</a> <small>(> 1.4.4)</small> and
- <a href="http://jquery.com">jQuery</a> <small>(> 1.7.0)</small> or
- <a href="http://zeptojs.com/">Zepto</a>.
- </p>
- </section>
- <section id="introduction">
- <h2>Introduction</h2>
- <p>
- Backbone-relational.js provides one-to-one, one-to-many and many-to-one relations
- between models for Backbone. To use relations, extend <a href="#RelationalModel"><strong>Backbone.RelationalModel</strong></a>
- (instead of a regular <a href="http://backbonejs.org/#Model">Backbone.Model</a>) and define a
- <a href="#RelationalModel-relations"><q>relations</q></a> property, containing an array of option objects.
- Each relation must define (at least) the <a href="#relations-type"><q>type</q></a>, <a href="#relations-key"><q>key</q></a>,
- and <a href="#relations-relatedModel"><q>relatedModel</q></a>. Available relation types are
- <a href="#Relation-HasOne"><q>Backbone.HasOne</q></a> and <a href="#Relation-HasMany"><q>Backbone.HasMany</q></a>.
- </p>
- <p>
- Backbone-relational's main features include:
- </p>
- <ul>
- <li>
- Bidirectional relations, which notify related models of changes through events.
- </li>
- <li>
- Control how relations are serialized using the <a href="#relations-includeInJSON"><q>includeInJSON</q></a> option.
- </li>
- <li>
- Automatically convert nested objects in a model's attributes into model instances (using the
- <a href="#relations-createModels"><q>createModels</q></a> option, which is <q>true</q> by default).
- </li>
- <li>
- Lazily retrieve a set of related models through the <a href="#RelationalModel-getAsync"><q>getAsync</q></a>
- method.
- </li>
- <li>
- Determine the type of HasMany collections with <a href="#relations-collectionType"><q>collectionType</q></a>.
- </li>
- </ul>
- <p>
- You can also bind new events to a <strong>Backbone.RelationalModel</strong> for an:
- </p>
- <ul>
- <li>
- <strong>addition</strong> to a HasMany relation with <a href="#RelationalModel-events">add:<key></a>.
- </li>
- <li>
- <strong>removal</strong> from a HasMany relation with <a href="#RelationalModel-events">remove:<key></a>.
- </li>
- <li>
- <strong>reset</strong> of a HasMany relation with <a href="#RelationalModel-events">reset:<key></a>.
- </li>
- <li>
- <strong>changes</strong> to the contents of a HasMany or HasOne relations with <a href="#RelationalModel-events">change:
- <key></a>.
- </li>
- </ul>
- </section>
- <section id="installation">
- <h2>Installation</h2>
- <p>
- Backbone-relational depends on <a href="http://backbonejs.org/">Backbone.js</a> (and thus on
- <a href="http://underscorejs.org">Underscore.js</a>). Include Backbone-relational right after Backbone
- and Underscore:
- </p>
- <pre class="language-markup"><code class="language-markup"><!--
- --><script type="text/javascript" src="./js/underscore.js"></script>
- <!-- --><script type="text/javascript" src="./js/backbone.js"></script>
- <!-- --><script type="text/javascript" src="./js/backbone-relational.js"></script>
- </code></pre>
- <p class="notice">
- Note for <strong>CoffeeScript</strong> users: due to the way the <q>extends</q> keyword is implemented in
- CoffeeScript, you may have to make an extra call to <a href="#RelationalModel-setup"><q>setup</q></a> for
- your models. See the <a href="#RelationalModel-setup"><q>setup</q></a> documentation for details.
- </p>
- </section>
- <section id="RelationalModel">
- <h2>
- Backbone.RelationalModel
- </h2>
- <p>
- When using Backbone-relational, each model defining (or receiving) <q>relations</q> must extend
- <strong>Backbone.RelationalModel</strong> in order to function. <strong>Backbone.RelationalModel</strong>
- introduces a couple of new methods, events and properties. It's important to know which are properties,
- which are methods of an instance, and which operate on the type itself.
- These three subcategories are detailed below.
- </p>
- <p>
- <strong>Properties</strong> can be defined when extending Backbone.RelationalModel, or a subclass thereof.
- </p>
- <ul class="small">
- <li><a href="#RelationalModel-relations">relations</a></li>
- <li><a href="#RelationalModel-subModelTypes">subModelTypes</a></li>
- <li><a href="#RelationalModel-subModelTypeAttribute">subModelTypeAttribute</a></li>
- </ul>
- <p>
- <strong>Instance methods</strong> operate on an instance of a type.
- </p>
- <ul class="small">
- <li><a href="#RelationalModel-getAsync">getAsync</a></li>
- <li><a href="#RelationalModel-getIdsToFetch">getIdsToFetch</a></li>
- <li><a href="#RelationalModel-getRelation">getRelation</a></li>
- <li><a href="#RelationalModel-getRelations">getRelations</a></li>
- <li><a href="#RelationalModel-set">set</a></li>
- <li><a href="#RelationalModel-toJSON">toJSON</a></li>
- </ul>
- <p>
- <strong>Static methods</strong> operate on the type itself, as opposed to operating on model instances.
- </p>
- <ul class="small">
- <li><a href="#RelationalModel-setup">setup</a></li>
- <li><a href="#RelationalModel-build">build</a></li>
- <li><a href="#RelationalModel-findOrCreate">findOrCreate</a></li>
- <li><a href="#RelationalModel-find">find</a></li>
- <li><a href="#RelationalModel-findModel">findModel</a></li>
- </ul>
- <h3 id="RelationalModel-properties">
- Properties
- </h3>
- <h4 class="code" id="RelationalModel-relations">
- relations<code>relation[]</code>
- </h4>
- <p>
- A <strong>Backbone.RelationalModel</strong> may contain an array of relation definitions. Each relation supports a number of
- options, of which <a href="#relations-relatedModel"><q>relatedModel</q></a>, <a href="#relations-key"><q>key</q></a> and
- <a href="#relations-type"><q>type</q></a> are mandatory. A relation could look like the following:
- </p>
- <pre class="language-javascript"><code id="example-zoo" class="language-javascript runnable"><!--
- -->Zoo = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'animals',
- relatedModel: 'Animal',
- collectionType: 'AnimalCollection',
- reverseRelation: {
- key: 'livesIn',
- includeInJSON: 'id'
- // 'relatedModel' is automatically set to 'Zoo'; the 'relationType' to 'HasOne'.
- }
- }]
- });
- Animal = Backbone.RelationalModel.extend({
- urlRoot: '/animal/'
- });
- AnimalCollection = Backbone.Collection.extend({
- model: Animal
- });
- // We've now created a fully managed relation. When you add or remove model from `zoo.animals`,
- // or update `animal.livesIn`, the other side of the relation will automatically be updated.
- var artis = new Zoo( { name: 'Artis' } );
- var lion = new Animal( { species: 'Lion', livesIn: artis } );
- // `animals` in `artis` now contains `lion`
- alert( artis.get( 'animals' ).pluck( 'species' ) );
- </code></pre>
- <pre class="language-javascript nomargin"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
- -->var amersfoort = new Zoo( { name: 'Dierenpark Amersfoort', animals: [ lion ] } );
- // `lion` now livesIn `amersfoort`, and `animals` in `artis` no longer contains `lion`
- alert( lion.get( 'livesIn' ).get( 'name' ) + ', ' + artis.get( 'animals' ).length );
- </code></pre>
- <section id="relations-key">
- <h4 class="code">
- key<code>relation.key</code>
- </h4>
- <p>
- Required. A string that references an attribute name on <a href="#relations-relatedModel"><q>relatedModel</q></a>.
- </p>
- <h4 class="code" id="relations-relatedModel">
- relatedModel<code>relation.relatedModel</code>
- </h4>
- <p>
- Required. A string that can be resolved to an object on the global scope, or a reference to a
- <strong>Backbone.RelationalModel</strong>. Also see <a href="#Store-addModelScope"><q>addModelScope</q></a>.
- </p>
- </section>
- <section id="relations-type">
- <h4 class="code">
- type<code>relation.type</code>
- </h4>
- <p>
- Required. A string that references a <a href="#Relation"><q>Backbone.Relation</q></a> type by name ("HasOne" or "HasMany"),
- or a direct reference to a relation type.
- </p>
- <p>
- You can model a one-to-one or a many-to-one relationship by declaring <q>type</q> as the string "HasOne", or by
- directly referencing <a href="#Relation-HasOne"><q>Backbone.HasOne</q></a>. A HasOne relation contains a single
- <strong>Backbone.RelationalModel</strong>. The default <q>reverseRelation.type</q> for a "HasOne" relation is
- "HasMany". This can be set to "HasOne" instead, to create a one-to-one relation.
- </p>
- <p>
- You can model a one-to-many relationship by declaring <q>type</q> as the string "HasMany", or by directly
- referencing <a href="#Relation-HasMany"><q>Backbone.HasMany</q></a>. A HasMany relation contains a Backbone.Collection,
- containing zero or more <strong>Backbone.RelationalModel</strong>s. The default <q>reverseRelation.type</q>
- for a HasMany relation is HasOne; this is the only option here, since many-to-many is not supported directly.
- </p>
- <p>
- It is possible model a many-to-many relationship using two <a href="#Relation-HasMany"><q>Backbone.HasMany</q></a>
- relations, with a link model in between:
- </p>
- </section>
- <pre class="language-javascript"><code class="language-javascript" id="example-job"><!--
- -->Person = Backbone.RelationalModel.extend({
- relations: [{
- type: 'HasMany',
- key: 'jobs',
- relatedModel: 'Job',
- reverseRelation: {
- key: 'person'
- }
- }]
- });
- // A link object between 'Person' and 'Company'
- Job = Backbone.RelationalModel.extend({
- defaults: {
- 'startDate': null,
- 'endDate': null
- }
- })
- Company = Backbone.RelationalModel.extend({
- relations: [{
- type: 'HasMany',
- key: 'employees',
- relatedModel: 'Job',
- reverseRelation: {
- key: 'company'
- }
- }]
- });
- </code></pre>
- <section id="relations-includeInJSON">
- <h4 class="code">
- includeInJSON<code>relation.includeInJSON</code>
- </h4>
- <p>
- A boolean, a string referencing one of the model's attributes, or an array of strings referencing model
- attributes. Default: <q>true</q>.
- </p>
- <p>
- Determines how the contents of a relation will be serialized following a call to the
- <a href="#RelationalModel-toJSON"><q>toJSON</q></a> method. If you specify a:
- </p>
- <ul>
- <li>
- <strong>Boolean</strong>: a value of true serializes the full set of attributes on the related model(s).
- Set to false to exclude the relation completely.
- </li>
- <li>
- <strong>String</strong>: include a single attribute from the related model(s). For example, 'name', or
- <q>Backbone.Model.prototype.idAttribute</q> to include ids.
- </li>
- <li>
- <strong>String[]</strong>: includes the specified attributes from the related model(s).
- </li>
- </ul>
- <p>
- Specifying <q>true</q> will cascade, meaning the relations of nested model will get serialized as well,
- until either a different value is found for <q>includeInJSON</q> or we encounter a model that has already
- been serialized.
- </p>
- </section>
- <section id="relations-autoFetch">
- <h4 class="code">
- autoFetch<code>relation.autoFetch</code>
- </h4>
- <p>
- A boolean or an object. Default: <q>false</q>.
- </p>
- <p>
- If this property is set to <q>true</q>, when a model is instantiated the related model is
- automatically fetched using <a href="#RelationalModel-getAsync"><q>getAsync</q></a>. The
- value of the property can also be an object. In that case the object is passed to
- <a href="#RelationalModel-getAsync"><q>getAsync</q></a> as the options parameter.
- </p>
- <p>
- Note that <q>autoFetch</q> operates independently from other `fetch` operations,
- including those that may have fetched the current model.
- </p>
- </section>
- <pre class="language-javascript"><code class="language-javascript"><!--
- -->var Shop = Backbone.RelationalModel.extend({
- relations: [
- {
- type: Backbone.HasMany,
- key: 'customers',
- relatedModel: 'Customer',
- autoFetch: true
- },
- {
- type: Backbone.HasOne,
- key: 'address',
- relatedModel: 'Address',
- autoFetch: {
- success: function( model, response ) {
- //...
- },
- error: function( model, response ) {
- //...
- }
- }
- }
- ]
- });
- </code></pre>
- <section id="relations-collectionType">
- <h4 class="code">
- collectionType<code>relation.collectionType</code>
- </h4>
- <p>
- A string that can be resolved to an object type on the global scope, or a reference to a
- <strong>Backbone.Collection</strong> type.
- </p>
- <p>
- Determine the type of collections used for a HasMany relation. If you define a
- url(models<Backbone.Model[]>) function on the specified collection, this enables
- <a href="#RelationalModel-getAsync"><q>getAsync</q></a> to fetch all missing models in one request,
- instead of firing a separate request for each.
- </p>
- <h4 class="code" id="relations-collectionKey">
- collectionKey<code>relation.collectionKey</code>
- </h4>
- <p>
- A string or a boolean. Default: <q>true</q>.
- </p>
- <p>
- Used to create a back reference from the <strong>Backbone.Collection</strong> used for a HasMany relation to the model on
- the other side of this relation. By default, the relation's key attribute will be used to create a reference to
- the RelationalModel instance from the generated collection. If you set <q>collectionKey</q> to a string,
- it will use that string as the reference to the RelationalModel, rather than the
- relation's key attribute. If you don't want this behavior at all, set <q>collectionKey</q> to <q>false</q>
- (or any falsy value) and this reference will not be created.
- </p>
- </section>
- <section id="relations-collectionOptions">
- <h4 class="code">
- collectionOptions<code>relation.collectionOptions</code>
- </h4>
- <p>
- An options hash, or a function that accepts an instance of a <strong>Backbone.RelationalModel</strong> and returns an options
- hash.
- </p>
- <p>
- Used to provide options for the initialization of the collection in the 'Many'-end of a HasMany relation. Can be
- an options hash or a function that should take the instance in the 'One'-end of the 'HasMany' relation and return
- an options hash.
- </p>
- </section>
- <section id="relations-createModels">
- <h4 class="code">
- createModels<code>relation.createModels</code>
- </h4>
- <p>
- A boolean. Default: <q>true</q>.
- </p>
- <p>
- Specifies whether models will be created from nested objects or not.
- </p>
- </section>
- <section id="relations-keySource">
- <h4 class="code">
- keySource<code>relation.keySource</code>
- </h4>
- <p>
- A string that references an attribute to deserialize data for <a href="#relations-relatedModel"><q>relatedModel</q></a> from.
- </p>
- <p>
- 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. For example, a Rails backend may provide the keys suffixed
- with <q>_id</q> or <q>_ids</q>. The behavior for <q>keySource</q> corresponds to the following rules:
- </p>
- <p>
- When a relation is instantiated, the contents of the <q>keySource</q> are used as its initial data. The
- application uses the regular key attribute to interface with the relation and the models in it; the
- <q>keySource</q> is not available as an attribute for the model. So you may be provided with data containing
- <q>animal_ids</q>, while you want to access this relation as <q>zoo.get('animals')</q>.
- </p>
- <p class="warning">
- Note that setting <q>keySource</q> will set <a href="#relations-keyDestination"><q>keyDestination</q></a>
- to the same value, if it isn't specified itself.
- This means that when saving zoo, the animals attribute will be serialized back into the <q>animal_ids</q> key.
- </p>
- <p class="warning">
- WARNING: when using a keySource, you should not use that attribute name for other purposes.
- </p>
- </section>
- <section id="relations-keyDestination">
- <h4 class="code">
- keyDestination<code>relation.keyDestination</code>
- </h4>
- <p>
- A string that references an attribute to serialize <a href="#relations-relatedModel"><q>relatedModel</q></a> into.
- </p>
- <p>
- Used to override key (and <a href="#relations-keySource"><q>keySource</q></a>) when determining what attribute to be
- written into when serializing a relation, since the server backing your relations may use different naming
- conventions. For example, a Rails backend may expect the keys to be suffixed with _attributes for nested
- attributes.
- </p>
- <p>
- When calling <a href="#RelationalModel-toJSON"><q>toJSON</q></a> on a model (either via
- <strong>Backbone.Sync</strong>, or directly), the data in the key attribute is transformed and assigned to the
- <q>keyDestination</q>.
- </p>
- <p>
- So you may want a relation to be serialized into the animals_attributes key, while you want to access this
- relation as <q>zoo.get( 'animals' );</q>.
- </p>
- <p class="warning">
- WARNING: when using a <q>keyDestination</q>, you should not use that attribute name for other purposes.
- </p>
- </section>
- <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
- -->var FarmAnimal = Animal.extend();
- // This `Farm` is confused, like legacy stuff can be. It wants its data back on a completely
- // different key than it supplies it on. We want to use a different one in our app as well.
- var Farm = Backbone.RelationalModel.extend({
- relations: [{
- type: Backbone.HasMany,
- key: 'animals',
- keySource: 'livestock',
- keyDestination: 'pets',
- relatedModel: FarmAnimal,
- reverseRelation: {
- key: 'farm',
- includeInJSON: 'name'
- }
- }]
- });
- // Create a `Farm`; parse `species`, add to `animals`, output goes to `pets`.
- var farm = new Farm( { name: 'Old MacDonald', livestock: [ { species: 'Sheep' } ] } );
- farm.get( 'animals' ).add( { species: 'Cow' } );
- alert( JSON.stringify( farm.toJSON(), null, 4 ) );
- </code></pre>
- <section id="relations-parse">
- <h4 class="code">
- parse<code>relation.parse</code>
- </h4>
- <p>
- A boolean. Default: <q>false</q>.
- </p>
- <p>
- If you have a relation where the models should be parsed when data is being set, specify `parse: true`.
- </p>
- </section>
- <section id="relations-reverseRelation">
- <h4 class="code">
- reverseRelation<code>relation.reverseRelation</code>
- </h4>
- <p>
- An object specifying the relation pointing back to this model from <a href="#relations-relatedModel"><q>relatedModel</q></a>.
- </p>
- <p>
- If the relation should be bidirectional, specify the details for the reverse relation here. It's only mandatory
- to supply a <a href="#relations-key"><q>key</q></a>; <a href="#relations-relatedModel"><q>relatedModel</q></a> is automatically
- set. The default type for a <q>reverseRelation</q> 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 <q>reverseRelation</q> with
- type HasMany as well; please see Many-to-many relations on how to model these type of relations.
- </p>
- <p class="warning">
- Note that if you define a relation (plus a reverseRelation) on a model, but don't actually create an instance
- of that model, it is possible <q>initializeRelations</q> will never get called, and the reverseRelation
- will not be initialized. This can happen when <q>extend</q> has been overridden, or redefined as in CoffeeScript.
- See <a href="#RelationalModel-setup">setup</a>.
- </p>
- </section>
- <section id="RelationalModel-subModelTypes">
- <h4 class="code">
- subModelTypes<code>relationalModel.subModelTypes(attributes<object>, [options<object>])</code>
- </h4>
- <p>
- An object. Default: <q>{}</q>.
- </p>
- <p>
- A mapping that defines what submodels exist for the model (the superModel) on which
- <q>subModelTypes</q> is defined. The keys are used to match the
- <a href="#RelationalModel-subModelTypeAttribute"><q>subModelTypeAttribute</q></a> when deserializing, and the values
- determine what type of submodel should be created for a key. When building model instances from data, we need to
- determine what kind of object we're dealing with in order to create instances of the right subModel type. This
- is done by finding the model for which the key is equal to the value of the
- <a href="#RelationalModel-subModelTypeAttribute"><q>subModelTypeAttribute</q></a> attribute on the passed in data.
- </p>
- <p>
- Each subModel is considered to be a proper submodel of its superclass (the model type you're extending), with a
- shared id pool. This means that when looking for an object of the supermodel's type, objects of a submodel's type
- can be returned as well, as long as the id matches. In effect, any relations pointing to the supermodel will look
- for instances of its submodels as well.
- </p>
- <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
- -->Mammal = Animal.extend({
- subModelTypes: {
- 'primate': 'Primate',
- 'carnivore': 'Carnivore'
- }
- });
- Primate = Mammal.extend();
- Carnivore = Mammal.extend();
- MammalCollection = AnimalCollection.extend({
- model: Mammal
- });
- // Create a collection that contains a 'Primate' and a 'Carnivore'.
- var mammals = new MammalCollection([
- { id: 3, species: 'chimp', type: 'primate' },
- { id: 5, species: 'panther', type: 'carnivore' }
- ]);
- var chimp = mammals.get( 3 );
- alert( 'chimp is an animal? ' + ( chimp instanceof Animal ) + '\n' +
- 'chimp is a carnivore? ' + ( chimp instanceof Carnivore ) + '\n' +
- 'chimp is a primate? ' + ( chimp instanceof Primate ) );
- </code></pre>
- <p>
- Suppose that we have an Mammal model and a Primate model extending Mammal. If we have a Primate object with id 3,
- this object will be returned when we have a relation pointing to a Mammal with id 3, as Primate is regarded a
- specific kind of Mammal; it's just a Mammal with possibly some primate-specific properties or methods.
- </p>
- <p class="warning">
- Note that this means that there cannot be any overlap in ids between instances of Mammal and Primate, as the
- Primate with id 3 will be the Mammal with id 3.
- </p>
- </section>
- <section id="RelationalModel-subModelTypeAttribute">
- <h4 class="code">
- subModelTypeAttribute<code>relationalModel.subModelTypeAttribute</code>
- </h4>
- <p>
- A string. Default: <q>type</q>.
- </p>
- <p>
- The <q>subModelTypeAttribute</q> is a references an attribute on the data
- used to instantiate <a href="#relations-relatedModel"><q>relatedModel</q></a>. The attribute that will be checked to
- determine the type of model that should be built when a raw object of attributes is set as the related value,
- and if the <a href="#relations-relatedModel"><q>relatedModel</q></a> has one or more submodels.
- </p>
- </section>
- <h3 id="RelationalModel-instance-methods">
- Instance methods
- </h3>
- <section id="RelationalModel-getAsync">
- <h4 class="code">
- getAsync<code>relationalModel.getAsync(attr<string>, [options<object>], [refresh<boolean>])</code>
- </h4>
- <p>
- Returns: <q>jQuery.Deferred</q> A <a href="http://api.jquery.com/category/deferred-object/">jQuery promise</a>
- </p>
- <p>
- Get an attribute's value asynchronously. If available, the local value will be returned.
- If <q>attr</q> is a relation and one or more of its models are not available, they will be fetched.
- </p>
- <p>
- This can be used specifically for lazy-loading scenarios.
- Only models are referenced in the attributes but have not been found/created yet are fetched.
- Setting <q>options.refresh</q> to true will fetch all model(s) from the server.
- In that case, any model that already exists will be updated with the retrieved data.
- The <q>options</q> object specifies options to be passed to <a href="http://backbonejs.org/#Sync">Backbone.Sync</a>.
- </p>
- <p>
- By default, a separate request will be fired for each model that is to be fetched from the server (if `key` references a collection).
- However, if your server/API supports it, you can fetch the set of models in one request by specifying a
- collectionType for the relation you call getAsync on. The <a href="#relations-collectionType"><q>collectionType</q></a>
- should have an overridden <a href="http://backbonejs.org/#Collection-url"><q>url</q></a>
- method that allows it to construct a url for an array of models. See <a href="#example-person">this example</a>
- or <a href="https://github.com/PaulUithol/backbone-tastypie">Backbone-tastypie</a> for an example.
- </p>
- </section>
- <section id="RelationalModel-getIdsToFetch">
- <h4 class="code">
- getRelations<code>relationModel.getIdsToFetch(attr<string|Backbone.Relation>, )</code>
- </h4>
- <p>
- Returns: <q>Array</q> A list of the ids that will be fetched when calling <q>getAsync</q>.
- </p>
- </section>
- <section id="RelationalModel-getRelation">
- <h4 class="code">
- getRelation<code>relationModel.getRelation(attr<string>)</code>
- </h4>
- <p>
- Returns: <q>Backbone.Relation</q> A single initialized relation on the model.
- </p>
- </section>
- <section id="RelationalModel-getRelations">
- <h4 class="code">
- getRelations<code>relationModel.getRelations()</code>
- </h4>
- <p>
- Returns: <q>Backbone.Relation[]</q> The set of initialized relations on the model.
- </p>
- </section>
- <section id="RelationalModel-set">
- <h4 class="code">
- set<code>set(key<string>, value, [options<object>]) <strong>or</strong> set(attributes<object>, [options<object>])</code>
- </h4>
- <p>
- Returns: <q>Backbone.RelationalModel</q> The model instance.
- </p>
- <p>
- The <q>set</q> method is overridden so that setting a value on an "relational" attribute will update that relation.
- This is especially important to keep in mind for <q>HasMany</q> relations (which are backed by a <q>Backbone.Collection</q>).
- For these, calling <q>set</q> can be thought of as being equivalent to calling <q>update</q> on the collection itself,
- including how the options are handled.
- </p>
- <p>
- Additional <q>options</q> for a <q>HasMany</q> relation:
- </p>
- <dl>
- <dt><q>add</q></dt>
- <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>
- <dt><q>merge</q></dt>
- <dd>Default: <q>true</q>. If true, existing models will be updated with the given attributes.</dd>
- <dt><q>remove</q></dt>
- <dd>Default: <q>true</q>. If true, models present in the relation but not specified in the arguments will be removed.</dd>
- </dl>
- </section>
- <section id="RelationalModel-toJSON">
- <h4 class="code">
- toJSON<code>relationModel.toJSON(name<string>)</code>
- </h4>
- <p>
- Returns: <q>Object</q> The JSON representation of the model.
- See <a href="http://backbonejs.org/#Model-toJSON">Backbone.Model.toJSON</a>.
- </p>
- <p>
- The regular <q>toJSON</q> function has been overridden and modified to serialize (nested) relations
- according to their <a href="#relations-includeInJSON"><q>includeInJSON</q></a>, <a href="#relations-keySource"><q>keySource</q></a>,
- and <a href="#relations-keyDestination"><q>keyDestination</q></a> options.
- </p>
- </section>
- <h3 id="RelationalModel-static-methods">
- Static methods
- </h3>
- <section id="RelationalModel-setup">
- <h4 class="code">
- setup<code>relationModel.setup()</code>
- </h4>
- <p>
- Returns: <q>Backbone.RelationalModel.constuctor</q> The type.
- </p>
- <p>
- Initialize the relations and submodels for the model type. Normally, this happens automatically, but it doesn't if
- you're using CoffeeScript and using the syntax <q>class MyModel extends Backbone.RelationalModel</q> instead of
- the JavaScript equivalent of <q>MyModel = Backbone.RelationalModel.extend()</q>.
- </p>
- <p>
- This has advantages in CoffeeScript, but it also means that <q>Backbone.Model.extend</q> will not get called.
- Instead, CoffeeScript generates piece of code that would normally achieve the same. However, <q>extend</q> is also
- the method that Backbone-relational overrides to set up relations as you're defining your <q>Backbone.RelationalModel</q> subclass.
- </p>
- <p>
- In this case, you should call <q>setup</q> manually after defining your subclass CoffeeScript-style. For example:
- </p>
- <p class="warning">
- Note: this is a static method. It operates on the model type itself, not on an instance of it.
- </p>
- </section>
- <pre class="language-javascript"><code class="language-javascript"><!--
- -->class Animal extends Backbone.RelationalModel
- urlRoot: "/animal"
- class Mammal extends Animal
- subModelTypes:
- "primate": "Primate"
- "carnivore": "Carnivore"
- relations: [
- # More relations
- ]
- Mammal.setup()
- class Primate extends Mammal
- class Carnivore extends Mammal
- chimp = Mammal.build( { id: 3, species: "chimp", type: "primate" } )
- </code></pre>
- <section id="RelationalModel-build">
- <h4 class="code">
- build<code>relationalModel.build(attributes<object>, [options<object>])</code>
- </h4>
- <p>
- Returns: <q>Backbone.RelationalModel</q> A model instance.
- </p>
- <p>
- Create an instance of a model, taking into account what submodels have been defined.
- </p>
- <p class="warning">
- Note: this is a static method. It operates on the model type itself, not on an instance.
- </p>
- </section>
- <section id="RelationalModel-findOrCreate">
- <h4 class="code">
- findOrCreate
- <code>relationalModel.findOrCreate(attributes<string|number|object>, [options<object>])</code>
- </h4>
- <p>
- Returns: <q>Backbone.RelationalModel</q> A model instance.
- </p>
- <p>
- Search for a model instance in the <a href="#Store">Backbone.Relational.store</a>, and return the model if found.
- 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>.
- </p>
- <p>
- Accepted <q>options</q>:
- </p>
- <dl>
- <dt><q>create</q></dt>
- <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>
- <dt><q>merge</q></dt>
- <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>
- <dt><q>parse</q></dt>
- <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
- as a function (<q>this</q> will not point to a model), instead of as a method.</dd>
- </dl>
- <p class="warning">
- Note: this is a static method. It operates on the model type itself, not on an instance of it.
- </p>
- </section>
- <section id="RelationalModel-find">
- <h4 class="code">
- find
- <code>relationalModel.find(attributes<string|number|object>, [options<object>])</code>
- </h4>
- <p>
- Returns: <q>Backbone.RelationalModel</q> A model instance.
- </p>
- <p>
- A shortcut for <a href="#RelationalModel-findOrCreate"><q>findOrCreate</q></a> that uses <q>create: false</q>.
- Accepts the same options as <q>findOrCreate</q> (except for <q>create</q>).
- </p>
- <p class="warning">
- Note: this is a static method. It operates on the model type itself, not on an instance of it.
- </p>
- </section>
- <section id="RelationalModel-findModel">
- <h4 class="code">
- findModel
- <code>relationalModel.findModel(attributes<string|number|object>)</code>
- </h4>
- <p>
- Returns: <q>Backbone.RelationalModel</q> A model instance.
- </p>
- <p>
- A hook to override the matching when updating (or creating) a model.
- The default implementation is to look up the model by id in the store:
- <q>return Backbone.Relational.store.find( this, attributes );</q>
- </p>
- <p>
- Custom behavior is useful in cases where (a collection of) nested data gets saved to the server.
- Consider saving the following model:
- </p>
- <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
- -->var zoo = new Zoo( { id: 1, name: 'Artis', animals: [
- { species: 'Giraffe' },
- { species: 'Camel' }
- ] } );
- alert( JSON.stringify( zoo.toJSON(), null, 4 ) );
- </code></pre>
- <p>
- Normally, whatever you use as server-side logic will respond by creating two animals, and assigning them
- an id. The response will be used by Backbone-relational to update existing models.
- However, updating a model starts by looking up the local model with the same id; and in this case,
- Backbone-relational does not know which local models corresponds to which created animal with an id.
- A simple fix in this case would be to add a fallback option for the matching by using the animal's
- species. Do note you'd want to use a more robust method usually, such as using a new model's <q>cid</q>.
- </p>
- <pre class="language-javascript"><code class="language-javascript runnable" data-setup="#example-zoo"><!--
- -->Zoo.findModel = function( attributes ) {
- // Try to find an instance of 'this' model type in the store
- var model = Backbone.Relational.store.find( this, attributes );
- if ( !model && _.isObject( attributes ) ) {
- var coll = Backbone.Relational.store.getCollection( this );
- model = coll.find( function( m ) {
- return m.species === attributes.species;
- });
- }
- return model;
- };
- </code></pre>
- <p class="warning">
- Note: this is a static method. It operates on the model type itself, not on an instance of it.
- </p>
- </section>
- <section id="RelationalModel-events">
- <h4>
- Catalog of Events
- </h4>
- <p>
- Backbone-relational makes a couple of additional events available to you, on top of the events already found in Backbone.
- </p>
- <ul class="small">
- <li>
- An <strong>"add"</strong> event is triggered on addition to a HasMany relation. Bind to:<br/>
- <q>add:<key></q> →<code>function(addedModel<Backbone.Model>, related<Backbone.Collection>)</code>
- </li>
- <li>
- A <strong>"remove"</strong> event is triggered on removal from a HasMany relation. Bind to:<br/>
- <q>remove:<key></q> →<code>function(removedModel<Backbone.Model>, related<Backbone.Collection>)</code>
- </li>
- <li>
- A <strong>"change"</strong> event is triggered on changes to the contents of both HasOne and HasMany relations. Bind to:<br/>
- <q>change:<key></q> →<code>function(model<Backbone.Model>, related<Backbone.Model|Backbone.Collection>)</code>
- </li>
- </ul>
- </section>
- </section>
-
- <section id="Relation">
- <h2 >Backbone.Relation</h2>
- <p>
- Each <a href="#RelationalModel-relations">relation</a> definition on a model is used to create in instance of a <q>Backbone.Relation</q>; either
- a <q>Backbone.HasOne</q> or a <q>Backbone.HasMany</q>.
- </p>
- <h4 class="code" id="Relation-HasOne">
- Backbone.HasOne
- </h4>
- <p>
- Defines a <strong>HasOne</strong> relation. When defining a <a href="#relations-reverseRelation">reverseRelation</a>, the default type
- will be <strong>HasMany</strong>. However, this can also be set to <strong>HasOne</strong> to define a one-to-one relation.
- </p>
- <h4 class="code" id="Relation-HasMany">
- Backbone.HasMany
- </h4>
- <p>
- Defines a <strong>HasMany</strong> relation. When defining a <a href="#relations-reverseRelation">reverseRelation</a>, the type
- will be <strong>HasOne</strong>.
- </p>
- </section>
- <section id="Store">
- <h2 >Backbone.Store</h2>
- <p>
- <strong>Backbone.Store</strong> is a global model cache. Per application, one instance is created (much like <q>Backbone.History</q>),
- which is accessible as <q>Backbone.Relational.store</q>.
- </p>
- <h4 class="code" id="Store-addModelScope">
- addModelScope<code>Backbone.Relational.store.addModelScope(scope<object>)</code>
- </h4>
- <p>
- Add a namespace on which models and collections are defined. This is especially useful when working in an
- environment without a shared global scope (like <q>window</q> is in a browser), where you'll need to tell
- the <q>store</q> where your models are defined, so it can resolve them to create and maintain relations.
- </p>
- <h4 class="code" id="Store-removeModelScope">
- removeModelScope<code>Backbone.Relational.store.removeModelScope()</code>
- </h4>
- <p>
- Remove a scope. This allows you to remove a scope you added previously, or to remove the default 'global'
- scope (<q>window</q> in the browser) scope to prevent Backbone-relational from resolving objects on it.
- </p>
- <h4 class="code" id="Store-reset">
- reset<code>Backbone.Relational.store.reset()</code>
- </h4>
- <p>
- Reset the <q>store</q> to its original state. This will disable relations for all models created up to this point,
- remove added model scopes, and removed all internal store collections.
- </p>
- <h4 class="code" id="Store-unregister">
- unregister<code>Backbone.Relational.store.unregister(type<Backbone.RelationalModel|Backbone.RelationalModel.constructor|Backbone.Collection>)</code>
- </h4>
- <p>
- Unregister a single model or a collection. Unregistering a model will remove a model from any relations it's involved in.
- Internally, unregister is called when a model has been destroyed. It can also be called explicitly to on models
- you don't want Backbone-relational to consider for relations anymore, for example to free up models used as (temporary) search results.
- </p>
- </section>
- <section id="examples">
- <h2 >Examples</h2>
- <p>
- <a href="http://antoviaque.org/docs/tutorials/backbone-relational-tutorial/">A tutorial by antoviaque</a>,
- and the <a href="https://github.com/antoviaque/backbone-relational-tutorial">accompanying git repository</a>.
- </p>
- <p>
- A basic working example to get you started:
- </p>
-
- <pre class="language-javascript"><code id="example-person-run1" class="language-javascript runnable" data-setup="#example-person"><!--
- -->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' ) );
- </code></pre>
- <pre class="language-javascript nomargin"><code id="example-person-run2" class="language-javascript runnable" data-setup="#example-person-run1"><!--
- -->// Load occupants 'person-2' and 'person-5', which don't exist yet, from the server
- ourHouse.getAsync( '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' ) );
- </code></pre>
- <pre class="language-javascript nomargin"><code id="example-person-run3" class="language-javascript runnable" data-setup="#example-person-run2"><!--
- -->// Move into `theirHouse`; triggers 'add:occupants' on ourHouse, and 'change:livesIn' on paul
- theirHouse = new House( { id: 'house-2' } );
- paul.set( { 'livesIn': theirHouse } );
- alert( 'theirHouse.occupants=' + theirHouse.get( 'occupants' ).pluck( 'name' ) );
- </code></pre>
- <p>This is achieved using the following relations and models:</p>
- <pre class="language-javascript"><code class="language-javascript" id="example-person"><!--
- -->House = Backbone.RelationalModel.extend({
- // 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'
- }
- }
- ]
- });
- Person = Backbone.RelationalModel.extend({
- relations: [
- { // Create a (recursive) one-to-one relationship
- type: Backbone.HasOne,
- key: 'user',
- relatedModel: 'User',
- reverseRelation: {
- type: Backbone.HasOne,
- key: 'person'
- }
- }
- ],
- initialize: function() {
- // do whatever you want :)
- }
- });
- PersonCollection = Backbone.Collection.extend({
- url: function( 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(';') + '/' : '' );
- }
- });
- User = Backbone.RelationalModel.extend();
- </code></pre>
- </section>
- <section id="change-log">
- <h2>Change Log</h2>
- <h4>Master
- <small>
- <span class="date">(future)</span> –
- <a href="https://github.com/PaulUithol/Backbone-relational/compare/0.8.8...master">diff</a> –
- <a href="https://raw.github.com/PaulUithol/Backbone-relational/master/backbone-relational.js">download</a>
- </small>
- </h4>
- <ul>
- <li>
- <a href="https://github.com/PaulUithol/Backbone-relational/commit/42b158d8ad5697a955a2c1e615824109dfc52234"><q>42b158d</q></a>
- Add <q>getIdsToFetch</q> to <q>Backbone.RelationalModel</q>.
- </li>
- <li>
- <a href="https://github.com/PaulUithol/Backbone-relational/commit/b7e71237d1218eec41ce69e1cf56e5eecdc96bef"><q>b7e7123</q></a>
- <q>getAsync</q> (the successor of <q>fetchRelated</q>) now return a single promise, instead of an array of request objects.
- </li>
- <li>
- <a href="https://github.com/PaulUithol/Backbone-relational/issues/467"><q>#467</q></a>:
- Improve lazy loading implemenatation. Add <q>getAsync</q> to <q>Backbone.RelationalModel</q>, which always
- 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