Handling Forms with Marionette.js

Marionette.js is an extension library for Backbone.js that offers many improvements and conveniences to cover common use cases for Backbone. On a recent project, I helped build a large single page application using Marionette.

One thing that Marionette lacks out of the box is a convenient way to manage form lifecycles, including validating and submitting forms with minimal overhead. To address this, I created a generic FormView class that extends Marionette’s ItemView and works with the backbone-validation plugin.

Without further ado, here is the Marionette FormView class I created:


class FormView extends Backbone.Marionette.ItemView
    constructor: ->
      @listenTo this, 'render', @hideActivityIndicator
      @listenTo this, 'render', @prepareModel
      @listenTo this, 'save:form:success', @success
      @listenTo this, 'save:form:failure', @failure
    delegateEvents: (events) ->
      @ui = _.extend @_baseUI(), _.result(this, 'ui')
      @events = _.extend @_baseEvents(), _.result(this, 'events')
      super events
    tagName: 'form'
    _baseUI: ->
      submit: 'input[type="submit"]'
      activityIndicator: '.spinner'
    _baseEvents: ->
      eventHash =
        'change [data-validation]': @validateField
        'blur [data-validation]':   @validateField
        'keyup [data-validation]':  @validateField
      eventHash["click #{@ui.submit}"] = @processForm
    createModel: ->
      throw new Error 'implement #createModel in your FormView subclass to return a Backbone model'
    prepareModel: ->
      @model = @createModel()
    validateField: (e) ->
      validation = $(e.target).attr('data-validation')
      value = $(e.target).val()
      if @model.preValidate validation, value
        @invalid @, validation
        @valid @, validation
    processForm: (e) ->
    updateModel: ->
      throw new Error 'implement #updateModel in your FormView subclass to update the attributes of @model'
    saveModel: ->
      callbacks =
        success: => @trigger 'save:form:success', @model
        error: => @trigger 'save:form:failure', @model
      @model.save {}, callbacks
    success: (model) ->
    onSuccess: (model) -> null
    failure: (model) ->
    onFailure: (model) -> null
    showActivityIndicator: ->
    hideActivityIndicator: ->
    setupValidation: ->
      Backbone.Validation.unbind this
      Backbone.Validation.bind this,
        valid: @valid
        invalid: @invalid
    valid: (view, attr, selector) =>
    invalid: (view, attr, error, selector) =>

Simplifying Form Handling

This class does a lot of the heavy lifting towards setting up your form for real-time validation. In order to implement a subclass of this, you only need to define 2 functions:

  1. createModel: This function tells your view how to create a model instance after each successful save.
  2. updateModel: This function tells your view how to read data out of your DOM and update the model.

Besides that, it’s just a simple matter of adding Backbone.validation specifiers to you model class and adding data-validation attributes to the correct HTML elements. I’ve included a simple example of a model, view, and template using the FormView below.

An Example


require.define 'task_model': (exports, require, module) ->
  module.exports = class TaskModel extends Backbone.Model
    urlRoot: '/tasks'
        required: true
        required: true
        oneOf: [1, 2, 3, '1', '2', '3']


require.define 'create_task_view': (exports, require, module) ->
  FormView = require 'form_view'
  TaskModel = require 'task_model'
  module.exports = class CreateTaskView extends FormView
    template: require 'templates/create_task_template'
    className: 'task-form'
      name: '[name="name"]'
      priority: '[name="priority"]'
      activityIndicator: '.loading'
    createModel: -> new TaskModel
    updateModel: ->
        name: @ui.name.val()
        priority: parseInt @ui.priority.val()
    onSuccess: (model) ->
      Backbone.trigger 'task:create', model


require.define 'templates/create_task_template': (exports, require, module) ->
  template = """
  <h2>Create A Task:</h2>
  <label for="name">Task Name: </label>
  <input type="text" name="name" data-validation="name"/>
  <label for="priority">Priority: </label>
  <select name="priority" data-validation="priority">
    <option value="1">Low</option>
    <option value="2"selected="true">Normal</option>
    <option value="3">High</option>
  <input type="submit" value="New Task">
  <p class="loading">Saving to server...</p>
  module.exports = _.template template

While Backbone+Marionette.js is not as full featured as a more comprehensive framework like EmberJS or AngularJS, its simplicity and easiness to understand still makes it one of my favorite Javascript stacks. The code in this post is available on Github. There is also a live demo of the code here.

Are you using Marionette.JS? What have been your experiences?