Browse files

New pattern: sub-views.

  • Loading branch information...
1 parent deb5b17 commit 152dd664a6b1f092161fbd08bebb90e9c4d7b073 @rstacruz rstacruz committed Jan 24, 2012
Showing with 127 additions and 0 deletions.
  1. +127 −0 README.md
View
127 README.md
@@ -372,6 +372,133 @@ next: function() {
}
```
+Sub views
+---------
+
+__The problem:__ Your view code is starting to bloat as it tries to do too many
+things in one class.
+
+__The solution:__ Break it apart into smaller sub-views.
+
+### The situation
+
+This is a common occurence if you have one _giant_ view that takes care of the
+entire page. View classes may become unwieldy once they get up to 200 lines.
+
+### Solution 1: Sub views
+
+It may be wise to delegate some areas of the view to be the reponsibility of
+another view.
+
+In this example, we have a view that handles the entire application "chrome."
+Let's break apart some of it's parts on it's `render()` function. Notice that
+we're using `this.$()` to select elements inside the `ChromeView`'s element
+itself.
+
+``` javascript
+App.ChromeView = Backbone.View.extend({
+ render: function() {
+ // Instanciate some "sub" views to handle the responsibilities of
+ // their respective elements.
+ this.sidebar = new App.SidebarView({ el: this.$(".sidebar") });
+ this.menu = new App.NavigationView({ el: this.$("nav") });
+ }
+});
+
+$(function() {
+ App.chrome = new App.ChromeView({ el: $("#chrome") });
+});
+```
+
+We will then be able to access the sub-views like so:
+
+``` javascript
+App.chrome.sidebar.toggle();
+
+App.chrome.menu.expand();
+```
+
+### Events
+
+All Backbone objects can emit [events][events]. To maintain the separation of
+responsibilities of the view classes, you may have the sub-views trigger
+events that the parent view would need (and vice versa).
+
+[events]: http://documentcloud.github.com/backbone/#Events
+
+For instance, we may implement `SidebarView` to trigger events when the sidebar
+is collapsed or expanded:
+
+``` javascript
+App.SidebarView = Backbone.View.extend({
+ toggle: function() {
+ if ($(this.el).is(':visible')) {
+ $(this.el).hide();
+ this.trigger('collapse'); // <==
+ } else {
+ $(this.el).show();
+ this.trigger('expand'); // <==
+ }
+ },
+});
+```
+
+And the parent view (`ChromeView`) may listen to them like so:
+
+``` javascript
+App.ChromeView = Backbone.View.extend({
+ render: function() {
+ this.sidebar = new App.SidebarView({ el: this.$(".sidebar") });
+
+ this.sidebar
+ .bind('collapse', this.onSidebarCollapse)
+ .bind('expand', this.onSidebarExpand);
+
+ // ...
+ }
+});
+```
+
+Splitting views
+---------------
+
+__The problem:__ Your view code is starting to bloat as it tries to do too many
+things in one class, and making sub-views with it's child elements is not an
+option.
+
+__The solution:__ Make a sub-view with the same element.
+
+Solution
+--------
+
+You can make 2 or more views that target the same element. This is useful when
+there are many controls in a view, but creating sub-views (with their scopes
+limited to a set of elements in the bigger view) may be too messy, or just not
+possible.
+
+In this example, `ChromeView` will make a sub-view that shares the same element
+as it does.
+
+``` javascript
+App.ChromeView = Backbone.View.extend({
+ events: {
+ 'click button': 'onButtonClick'
+ },
+ render: function() {
+ // Pass our own element to the other view.
+ this.tabs = new App.TabView({ el: this.el });
+ }
+});
+
+App.TabView = Backbone.View.extend({
+ // Notice this view has it's own events. They will not interfere with
+ ChromeView's events.
+ events: {
+ 'click nav.tabs a': 'switchTab'
+ },
+});
+```
+
Conventions
===========

0 comments on commit 152dd66

Please sign in to comment.