Skip to content

Commit

Permalink
For addyosmani#342 - some improvements, adding in nested models/colle…
Browse files Browse the repository at this point in the history
…ctions piece
  • Loading branch information
addyosmani committed Mar 29, 2013
1 parent 423d24e commit 669ad54
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 59 deletions.
Binary file modified backbone-fundamentals.epub
Binary file not shown.
71 changes: 55 additions & 16 deletions backbone-fundamentals.md
Original file line number Diff line number Diff line change
Expand Up @@ -5179,11 +5179,11 @@ In this section, we will review a number of common problems developers often exp
Perhaps the most frequent of these questions surround how to do more with Views. If you are interested in discovering how to work with nested Views, learn about view disposal and inheritance, this section will hopefully have you covered.
#### View Nesting
#### Working With Nested Views
**Problem**
What is the best approach for rendering and appending Subviews in Backbone.js?
What is the best approach for rendering and appending nested Views (or Subviews) in Backbone.js?
**Solution 1**
Expand Down Expand Up @@ -5324,8 +5324,8 @@ A sample implementation containing a single child view could be written:
var OuterView = Backbone.View.extend({
initialize: function() {
this.children = {};
var child = new Backbone.View();
this.children[child.cid] = child;
this.child = new Backbone.View();
this.children[this.child.cid] = this.child;
},

render: function() {
Expand All @@ -5338,7 +5338,6 @@ var OuterView = Backbone.View.extend({

```
The use of `cid`s (client ids) here is useful because it illustrates separating a model and its views by having views referenced by their instances and not their attributes. It's quite common to ask for all views that satisfy an attribute on their models, but if you have recursive subviews or repeated views (a common occurrance), you can't simply ask for views by attributes. That is, unless you specify additional attributes that separate duplicates. Using `cid`s solves this problem as it allows for direct references to views.
Expand All @@ -5351,7 +5350,13 @@ The Backbone extensions [Marionette](#marionette) and [Thorax](#thorax) provide
(Thanks to [Lukas](http://stackoverflow.com/users/299189/lukas) and [Ian Taylor](http://stackoverflow.com/users/154765/ian-storm-taylor) for these tips).
#### What is the best way to manage models in nested Views?
#### Managing Models In Nested Views
**Problem**
What is the best way to manage models in nested views?
**Solution**
In order to reach attributes on related models in a nested setup, models require some prior knowledge of each other, something which Backbone doesn't implicitly handle out of the box.
Expand Down Expand Up @@ -5379,7 +5384,6 @@ Now, we have already discussed a few options for how to construct nested Views u
See inline for comments on exactly what each step is enabling:
```javascript

// Define View A
Expand Down Expand Up @@ -5420,7 +5424,7 @@ var viewA = new ViewA({ model: ModelA });
```
#### Rendering Parent View from Child
#### Rendering A Parent View From A Child View
**Problem**
Expand Down Expand Up @@ -5460,12 +5464,10 @@ The child will trigger a "somethingHappened" event and the parent's render funct
(Thanks to Tal [Bereznitskey](http://stackoverflow.com/users/269666/tal-bereznitskey) for this tip)
#### Disposing View hierarchies
#### Disposing View Hierarchies
**Problem**
In the last question, we looked at how to effectively dispose of views to decrease memory usage.
Where your application is setup with multiple Parent and Child Views, it is also common to desire removing any DOM elements associated with such views as well as unbinding any event handlers tied to child elements when you no longer require them.
**Solution**
Expand All @@ -5478,7 +5480,6 @@ Backbone.View.prototype.close = function() {
this.onClose();
}
this.remove();
this.unbind();
};

NewView = Backbone.View.extend({
Expand Down Expand Up @@ -5512,7 +5513,7 @@ In most cases, the view removal should not affect any associated models. For exa
Note: You may also be interested in reading the about Marionette Composite Views in the Extensions part of the book.
#### Rendering View hierarchies
#### Rendering View Hierarchies
**Problem**
Expand All @@ -5531,6 +5532,44 @@ There is a working demo of this in action available [online](http://jsfiddle.net
And you can get the source code and documentation for [Marionette](https://github.com/marionettejs/backbone.marionette) too.
#### Working With Nested Models Or Collections
**Problem**
Backbone doesn't include support for nested models or collections out of the box, favoring the use of good patterns for modeling your structured data on the client side. How do I work around this?
**Solution**
As we've seen, it's common to create collections representing groups of models using Backbone. It's also however common to wish to nest collections within models, depending on the type of application you are working on.
Take for example a Building model that contains many Room models which could sit in a Rooms collection.
You could expose a `this.rooms` collection for each building, allowing you to lazy-load rooms once a building has been opened.
```javascript
var Building = Backbone.Model.extend({

initialize: function(){
this.rooms = new Rooms;
this.rooms.url = '/building/' + this.id + '/rooms';
this.rooms.on("reset", this.updateCounts);
},

// ...

});

// Create a new building model
var townHall = new Building;

// once opened, lazy-load the rooms
townHall.rooms.fetch({reset: true});
```
There are also a number of Backbone plugins which can help with nested data structures, such as [Backbone Relational](https://github.com/PaulUithol/Backbone-relational). This plugin handles one-to-one, one-to-many and many-to-one relations between models for Backbone and has some excellent [documentation](http://backbonerelational.org/).
#### Better Model Property Validation
**Problem**
Expand Down Expand Up @@ -5760,11 +5799,11 @@ That's it!
The Backbone.validateAll logic doesn't override the default Backbone logic by default and so it's perfectly capable of being used for scenarios where you might care more about field-validation [performance](http://jsperf.com/backbone-validateall) as well as those where you don't. Both solutions presented in this section should work fine however.
#### Multiple Backbone versions
#### Avoiding Conflicts With Multiple Backbone Versions
**Problem**
In some instances it may be necessary to use multiple versions of Backbone in the same project.
In instances out of your control, you may have to work around having more than one version of Backbone in the same page. How do you work around this without causing conflicts?
**Solution**
Expand Down Expand Up @@ -5798,7 +5837,7 @@ var Backbone19 = Backbone.noConflict();
```
#### Building Model and View hierarchies
#### Building Model And View Hierarchies
**Problem**
Expand Down
58 changes: 45 additions & 13 deletions backbone-fundamentals.rtf
Original file line number Diff line number Diff line change
Expand Up @@ -4015,9 +4015,9 @@ Thorax website
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs36 Common Problems & Solutions\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In this section, we will review a number of common problems developers often experience once they\u8217've started to work on relatively non-trivial projects using Backbone.js, as well as present potential solutions.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Perhaps the most frequent of these questions surround how to do more with Views. If you are interested in discovering how to work with nested Views, learn about view disposal and inheritance, this section will hopefully have you covered.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 View Nesting\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Working With Nested Views\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 What is the best approach for rendering and appending Subviews in Backbone.js?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 What is the best approach for rendering and appending nested Views (or Subviews) in Backbone.js?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution 1}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Since pages are composed of nested elements and Backbone views correspond to elements within the page, nesting views is an intuitive approach to managing a hierarchy of elements.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 The best way to combine views is simply using:\par}
Expand Down Expand Up @@ -4119,8 +4119,8 @@ var InnerView = Backbone.View.extend(\{\line
var OuterView = Backbone.View.extend(\{\line
initialize: function() \{\line
this.children = \{\};\line
var child = new Backbone.View();\line
this.children[child.cid] = child;\line
this.child = new Backbone.View();\line
this.children[this.child.cid] = this.child;\line
\},\line
\line
render: function() \{\line
Expand Down Expand Up @@ -4148,7 +4148,10 @@ Lukas
Ian Taylor
}}}
for these tips).\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 What is the best way to manage models in nested Views?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Managing Models In Nested Views\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 What is the best way to manage models in nested views?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In order to reach attributes on related models in a nested setup, models require some prior knowledge of each other, something which Backbone doesn\u8217't implicitly handle out of the box.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 One approach is to make sure each child model has a \u8216'parent\u8217' attribute. This way you can traverse the nesting first up to the parent and then down to any siblings that you know of. So, assuming we have models modelA, modelB and modelC:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 \line
Expand Down Expand Up @@ -4203,7 +4206,7 @@ ViewB = Backbone.View.extend(\{\line
// viewA will create its own instance of ViewB\line
// from inside the initialize() method\line
var viewA = new ViewA(\{ model: ModelA \});\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Rendering Parent View from Child\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Rendering A Parent View From A Child View\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 How would one render a Parent View from one of its Children?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
Expand All @@ -4226,9 +4229,8 @@ this.trigger('somethingHappened');\par}
Bereznitskey
}}}
for this tip)\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Disposing View hierarchies\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Disposing View Hierarchies\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In the last question, we looked at how to effectively dispose of views to decrease memory usage.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Where your application is setup with multiple Parent and Child Views, it is also common to desire removing any DOM elements associated with such views as well as unbinding any event handlers tied to child elements when you no longer require them.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 The solution in the last question should be enough to handle this use case, but if you require a more explicit example that handles children, we can see one below:\par}
Expand All @@ -4237,7 +4239,6 @@ Bereznitskey
this.onClose();\line
\}\line
this.remove();\line
this.unbind();\line
\};\line
\line
NewView = Backbone.View.extend(\{\line
Expand Down Expand Up @@ -4268,7 +4269,7 @@ dira
}}}
for this tip)\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Note: You may also be interested in reading the about Marionette Composite Views in the Extensions part of the book.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Rendering View hierarchies\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Rendering View Hierarchies\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Let us say you have a Collection, where each item in the Collection could itself be a Collection. You can render each item in the Collection, and indeed can render any items which themselves are Collections. The problem you might have is how to render HTML that reflects the hierarchical nature of the data structure.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
Expand All @@ -4286,6 +4287,37 @@ online
Marionette
}}}
too.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Working With Nested Models Or Collections\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Backbone doesn\u8217't include support for nested models or collections out of the box, favoring the use of good patterns for modeling your structured data on the client side. How do I work around this?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 As we\u8217've seen, it\u8217's common to create collections representing groups of models using Backbone. It\u8217's also however common to wish to nest collections within models, depending on the type of application you are working on.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Take for example a Building model that contains many Room models which could sit in a Rooms collection.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 You could expose a {\f1 this.rooms} collection for each building, allowing you to lazy-load rooms once a building has been opened.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 var Building = Backbone.Model.extend(\{\line
\line
initialize: function()\{\line
this.rooms = new Rooms;\line
this.rooms.url = '/building/' + this.id + '/rooms';\line
this.rooms.on("reset", this.updateCounts);\line
\},\line
\line
// ...\line
\line
\});\line
\line
// Create a new building model\line
var townHall = new Building;\line
\line
// once opened, lazy-load the rooms\line
townHall.rooms.fetch(\{reset: true\});\par}
{\pard \ql \f0 \sa180 \li0 \fi0 There are also a number of Backbone plugins which can help with nested data structures, such as {\field{\*\fldinst{HYPERLINK "https://github.com/PaulUithol/Backbone-relational"}}{\fldrslt{\ul
Backbone Relational
}}}
. This plugin handles one-to-one, one-to-many and many-to-one relations between models for Backbone and has some excellent {\field{\*\fldinst{HYPERLINK "http://backbonerelational.org/"}}{\fldrslt{\ul
documentation
}}}
.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Better Model Property Validation\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 As we learned earlier in the book, the {\f1 validate} method on a Model is called by {\f1 set} (when the validate option is set) and {\f1 save}, and is passed the model attributes updated with the values passed to these methods.\par}
Expand Down Expand Up @@ -4478,9 +4510,9 @@ user.set(\{ 'firstname': 'Greg' \}, \{validate: true, validateAll: false\});\par
performance
}}}
as well as those where you don\u8217't. Both solutions presented in this section should work fine however.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Multiple Backbone versions\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Avoiding Conflicts With Multiple Backbone Versions\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In some instances it may be necessary to use multiple versions of Backbone in the same project.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 In instances out of your control, you may have to work around having more than one version of Backbone in the same page. How do you work around this without causing conflicts?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 Like most client-side projects, Backbone\u8217's code is wrapped in an immediately-invoked function expression:\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \f1 (function()\{\line
Expand All @@ -4499,7 +4531,7 @@ Backbone.noConflict = function() \{\line
// Backbone19 refers to the most recently loaded version,\line
// and `window.Backbone` will be restored to the previously\line
// loaded version\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Building Model and View hierarchies\par}
{\pard \ql \f0 \sa180 \li0 \fi0 \b \fs24 Building Model And View Hierarchies\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Problem}\par}
{\pard \ql \f0 \sa180 \li0 \fi0 How does inheritence work with Backbone? How can I share code between similar models and views? How can I call methods that have been overridden?\par}
{\pard \ql \f0 \sa180 \li0 \fi0 {\b Solution}\par}
Expand Down
Loading

0 comments on commit 669ad54

Please sign in to comment.