Skip to content

Instantly share code, notes, and snippets.

@wagnerjgoncalves
Last active April 28, 2016 00:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wagnerjgoncalves/477e3e1130bbaacf0eba to your computer and use it in GitHub Desktop.
Save wagnerjgoncalves/477e3e1130bbaacf0eba to your computer and use it in GitHub Desktop.

Backbone.js

backbone

Introduction

  • A library designed to be minimalist and useful in a wide variety of situations (non-opinionated)
  • Based in events communication/syncronization
  • Based in MVC (Model-View-Controller) structure

Structure

Model (Backbone.Model)

Models are the heart of any application, containing the interactive data as well as a large part of the logic surrounding it: conversions, validations, computed properties, and access control.

Backbone.Model provides a basic set of functionality for managing changes.

// Namespace definition
var SL = SL || {};

SL.Models = SL.Models || {};
SL.Views = SL.Views || {};
SL.Collections = SL.Collections || {};
SL.Router = SL.Router || {};
// Model definition

(function () {
  'use strict';

  SL.Models.Product = Backbone.Model.extend({
    urlRoot: function() {
      // In this case, POST to '/donuts' and PUT/GET to '/donuts/:id'
      return this.id ? '/products/' + this.id : '/products'; 
    },

    defaults: {
      title: '',
      quantity: 0,
      available: false
    },
    
    initialize: function(options) {
      // Do some initialization stuff...
      options = _.merge(defaults, options);

      // Register events...
      this.on('change:title', function(model){
        alert(
          capitalize(model.get('title'))
        );
      });
    },

    validate: function(attrs) {
      if(attrs.title.length < 0){
        return 'Name can\'t be blank';
      }
    }
  });

  var product = new SL.Models.Product({ id: 1 });
  
  product.fetch({
    success: function(prod) {
     prod.title = 'BluRay'
     
     prod.save();
     // PUTs the product beacause of the existent id
     // { id: 1, title: 'BluRay', ... }
    }
  });
  
  var newProduct = new SL.Models.Product({ title: 'Super Awesome DVD' });
 
  newProduct.save();
  
  // POST new product
  // { id: 2, title: 'DVD Bacana', quantity: 0, available: false }
})();

Collections (Backbone.Collection)

Is a structure of set of models with some functions.

collection

// Collection definition

(function () {
  'use strict';

  SL.Collections.ProductsCollection = Backbone.Collection.extend({
    // Use its model to deserialize and add methods configured on the model
    model: SL.Models.Product,
    url: '/products',

    initialize: function(options) {
      // Do some initialization stuff...
    },
    
    available: function () {
     return this.select(function(product) {
        return product.get('available') == true;
      });
    },
    
    unavailable: function () {
     return this.select(function(product) {
        return product.get('available') == false;
      });
    }
  });

  var products = new SL.Collections.ProductsCollection();
 
  products.available();
  products.unavailable();
})();

View (Backbone.View)

Is the Controller of MVC design pattern. It's called VIEW because it handles the rendering.

Provides a template library.

// View definition

(function () {
  'use strict';

  SL.Views.ProductView = Backbone.View.extend({    
    el: '.product',
    collection: SL.Collections.ProductsCollection,

    render: function() {
      // Do a lot of manipulations and insert on the dom
    }
  });
})();

Router (Backbone.Router)

Is a component to map a url to a function.

router

// Routing definition

(function () {
  'use strict';

  SL.Router = new Backbone.Router({
    routes: {
      'products': function() {
        // do stuff
      }
    }
  });
})();

Large Backbone Applications

When a Backbone application grows, maintaining it requires adding structure, adding boiderplate code, either through a custom set of conventions and components, or based on somebody elses framework.

Marionette.js

marionette

Introduction

  • Is a composite application library for Backbone.js that aims to simplify the construction of large scale JavaScript applications using: modular, event driven, messaging bus architecture
  • Is a Collection of common design and implementated patterns

What does Marionette give us?

  • Standardize the rendering process: Without any additional configuration, it will take a template that you specify with a View's template property, compile it with Underscore's templating function and pass it a model or collection.

  • Consistent View lifecycle: Views are initialized, rendered, shown, refreshed and destroyed.

  • Ability to define ad manage complex layouts: Marionette provides regions objects that define portions of the DOM that can display and swap out Views.

  • Helper to help DRY out the code: Marionette provides hooks to allow you to abstract details of the DOM.

  • Central Application initialization: Marionette provides the hability to set initializers that will run before the application start.

  • Memory management: Marionette resolves some memory leaks cause by Backbone.js.

Structure

Base Folder Structure

image

App Initialization

this.WL = (function(Backbone, Marionette){
  var App = Marionette.Application.extend({
    container: 'body',

   // The hability of define regions that can be sub-modules
    regions: {
      headerRegion: '[data-attribute=header-region]',
      sideBarRegion: '[data-attribute=sidebar-region]',
      mainRegion: '[data-attribute=main-region]'
    },

    initialize: function(options) {
    // Do some initialization stuff...
    },

    onStart: function() {
      this.module('HeaderApp').start();
      this.module('SideBarApp').start();
      this.module('MainApp').start();
    }
  });

  return new App();
})(Backbone, Marionette);

// App Start
$(document).ready(function() {
  WL.start();
});

Submodules

Module definition

this.WL.module('HeaderApp', function (HeaderApp, App, Backbone, Marionette, $, _) {
  this.startWithParent = false;
  var API;

  API = {
    show: function() {
      HeaderApp.Show.Controller.showHeader();
    }
  };

  // Message Bus Pattern
  HeaderApp.on('start', function(){
    API.show();
  });

  return HeaderApp;
});

Controller definition

this.WL.module('HeaderApp.Show', function(Show, App, Backbone, Marionette, $, _) {
  Show.Controller = {
    showHeader: function() {
      var headerView = this.getHeaderView();
      App.headerRegion.show(headerView);
    },

    getHeaderView: function() {
      return new Show.Header();
    }
  };

  return Show.Controller;
});

Item View definition

this.WL.module('HeaderApp.Show', function(Show, App, Backbone, Marionette, $, _) {
  Show.Header = Marionette.ItemView.extend({
    template: _.template('<div>Welcome aboard {{ name }}! <a class="login">login</a></div>'),

    defaults: {
      name: 'Visitor'
    },

    ui: {
      loginButton: 'a.login'
    },

    events: {
      'click @ui.headerButton' : 'login'
    }

    initialize: function(options) {
      this.mergeOptions(options, this.defaults);
    },

    onRender: function() {
      // Is executed when the render method has completed
      this.$el.addClass(this.id);
    }

    login: function() {
      // Do login stuff...
    }
  });

  return Show.Header;
});

Collection View definition

this.WL.module('HeaderApp.List', function(List, App, Backbone, Marionette, $, _) {
  List.LinkView = Marionette.ItemView.extend({
    template: _.template('<a class="super-link" href="{{ link_url }}">{{ link_name }}</a>'),

    // If you want to override the default serialization
    serializeData: function() {
      return {
        link_name: this.model.get('name'),
        link_url: this.model.get('url')
      };
    }
  });

  List.LinkCollectionView = Marionette.CollectionView.extend({
    template: 'path/to/template.jst',
    childView: List.LinkView
  });

  return List;
});

Template Cache

Provides a cache for retrieving templates from script blocks in HTML. This will improve the speed of subsequent calls to get a template.

(function () {
  var template = Marionette.TemplateCache.get('.super-link', options);
  template({ 
    link_name: 'My Lists', 
    link_url: 'http://example.com/my-lists'
  });
})();

Pros

  • Event-Oriented Architecture
  • Active Development
  • Large core team
  • Large community
  • Many companies use it
  • Dev Tools extension: Marionette Inspector for Chrome
  • Avoid boilerplate involved in writing Backbone apps
  • Reusable chuncks of UI logic

Cons

  • Focus only large scale applications

Bonus Feature

Marionette Inspector - Chrome Extension plugin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment