Backbone Conventions

Base Views

When defining a new View class, extend it directly from Backbone.View. Don’t use an intermediate BaseView class that introduces tight coupling and makes maintability difficult.

class MyShinyView extends Backbone.View {
  ...
}

Class inheritence

Avoid subclassing more than 2 levels from the base class. Subclassing more than several levels of inheritance may create JS patterns and logic difficult to follow and increasingly difficult to maintain. Take a step back and refactor with easily testable helper methods, mixins, or service objects.


// Good
class Animal extends Backbone.View {
  ...
}

// OK
class Turtle extends Animal {
  ...
}

// Bad
class NinjaTurtle extends Turtle {
  ...
}

Initializing defaults for constructor options

Use Underscore’s _.defaults() method to define default values for every acceptable constructor option:

class Person extends Backbone.View {
  initialize (options = {}) {
    this.options = _.defaults(options, {
      name: 'unknown name',
      role: 'worker'
    })
  }
}

Using templates for DOM creation

All Views must use HAML templates to create and define all HTML DOM structure that it will use to render and display data to the user. Avoid generating DOM in your JavaScript and instead use the imported HAML template to load the HTML into the view’s $el element.

# my_view.hamlc

.my-view
  .my-view__input
    %input(type='text')
  %button.my-view__button

// my_view.js

import MyViewTpl from 'my_view.hamlc'

class MyView () {
  initialize () {
    // Render template to the view DOM.
    this.$el.html(MyViewTpl)
  }
}

Event binding

model.on(…)

When you own the lifecycle of the model, it is ok to use .on for events.

class MyView extends Backbone.View {
  initialize () {
    // Lifecycle of this is owned by this view
    this.thing = new MyModel

    // When this view is removed this model and its events will be garbage
    // collected by the browser.   
    this.thing.on(...)
  }
}

this.listenTo(model, …)

Always use listenTo when attaching event listeners to a model that is passed in because the listeners will be removed when remove() is called. If .on is used, when a view is torn removed, the event listeners will still execute and lead to undesired functionality.

class MyView extends Backbone.View {
  initialize (options = {}) {
    // Model is passed in
    this.model = options.model

    // Attach listeners
    this.listenTo(this.model, ...)
  }

  remove () {
  }
}

let model = new Model()
let view = new MyView({model: model})

// This will automatically remove the event listeners on the model
view.remove()