Skip to content

Configuration

Alejandro Exojo edited this page Jun 12, 2014 · 19 revisions

There are several ways to configure Layouts and managed Views.

Options

There are a number of options you may wish to specify depending on how you wish to use LayoutManager.

Global

To configure at a global level, start with the configure call:

Backbone.Layout.configure({
  // Put options here.
});

From here you specify global values that will appear in options for all Views (managed by LayoutManager).

Definition

Useful for when you want options to exist for all instances created on a specific View.

Backbone.Layout.extend({
  // Put options here.
});

Instance

Lastly, you can specify options while creating a new instance, which can be very handy for on-the-fly Views.

new Backbone.Layout({ /* Put options here. */ });

Properties and methods

There are several predefined defaults that you may wish to change depending on your setup.

prefix

A string value that will be prefixed to the template property of all managed Views when fetchTemplate is called. You should always end with a trailing /.

Default:

prefix: ""

Example:

prefix: "app/templates/"

manage

A boolean value that determines if setupView should be called automatically for the Backbone.View. This is really useful to treat Views as Layouts.

Example:

manage: true

el

A boolean value that determines if the View's element should derive from the template or the View. If you set to false, the View's internal el will be set to the template.

Example:

el: false
Warning

It is not recommended nor supported to use multiple top level elements. This means if your template looks something like:

<h1>My awesome template</h1>
<ul></ul>

You will receive a console.warn message along with a stack trace in your developer tools console. There are many inconsistencies and problems related to multiple top level elements and Backbone. If you know the risks and understand the pitfalls you can suppress this warning with Backbone.Layout.configure({ suppressWarnings: true });.

suppressWarnings

This property may be set to true or false. If you set this to true all console.warn's will be silenced.

Default:

suppressWarnings: false

deferred

Uses jQuery deferreds for internal operation and the return value for render.

Default:

deferred: function() {
  return $.Deferred();
}

Example:

deferred: function() {
  return _.Deferred();
}

fetchTemplate(path)

Uses jQuery to find a selector and returns its innerHTML content as a template function. This method may be asynchronous.

Default:

fetchTemplate: function(path) {
  return _.template($(path).html());
}

Example:

fetchTemplate: function(path) {
  // To put this method into async-mode, simply call `async` and store the
  // return value (callback function).
  var done = this.async();

  // Asynchronously fetch the path in `template` and compile the contents
  // into a template.
  $.get(path, function(contents) {
    // Call the asynchronous callback with the function.
    done(_.template(contents));
  }, "text");
}

partial($root, $el, rentManager, manager)

Uses jQuery to find the View's location and inserts the rendered element there. Use the manager object to determine if the View is in insert mode, and if so, the View should be inserted instead of replacing the parent's contents. Defaults to replace via innerHTML. The rentManager argument refers to the root's __manager__ object. You can detect if the View is being inserted into a View that's managing it's own element, in which case you'd want filter instead of find.

You should typically not need to override this method.

Default:

partial: function($root, $el, rentManager, manager) {
  var $filtered;

  // If selector is specified, attempt to find it.
  if (manager.selector) {
    if (rentManager.noel) {
      $filtered = $root.filter(manager.selector);
      $root = $filtered.length ? $filtered : $root.find(manager.selector);
    } else {
      $root = $root.find(manager.selector);
    }
  }

  // Use the insert method if the parent's `insert` argument is true.
  if (rentManager.insert) {
    this.insert($root, $el);
  } else {
    this.html($root, $el);
  }
}

html($root, contents)

Override this with a custom HTML method, passed a root jQuery collection and an contents (may be a DOM Element or a String) to replace the innerHTML with. If this is overridden, it will be used when applying templates and when using setView.

Default:

html: function($root, contents) {
  $root.html(content);
}

htmlBatch(rootView, subViews, selector)

Used for inserting subViews in a single batch. This gives a small performance boost as we write to a disconnected fragment instead of to the DOM incrementally. LayoutManager will use this method internally when encountering a parent view with multiple children under the same selector.
jQuery will use a DocumentFragment for the batch update, but Cheerio in Node will not.

You should typically not need to override this method.

Default:

htmlBatch: function(rootView, subViews, selector) {
  // Shorthand the parent manager object.
  var rentManager = rootView.__manager__;
  // Create a simplified manager object that tells partial() where
  // place the elements and whether to use html() or insert().
  var manager = { selector: selector, insert: rentManager.insert };

  // Get the elements to be inserted into the root view.
  var els = _.reduce(subViews, function(memo, sub) {
    // Check if keep is present - do boolean check in case the user
    // has created a `keep` function.
    var keep = typeof sub.keep === "boolean" ? sub.keep : sub.options.keep;
    // If a subView is present, don't push it.  This can only happen if
    // `keep: true`.  We do the keep check for speed as $.contains is not
    // cheap.
    var exists = keep && $.contains(rootView.el, sub.el);

    // If there is an element and it doesn't already exist in our structure
    // attach it.
    if (sub.el && !exists) {
      memo.push(sub.el);
    }

    return memo;
  }, []);

  // Use partial to apply the elements. Wrap els in jQ obj for cheerio.
  return this.partial(rootView.$el, $(els), rentManager, manager);
}

insert($root, $el)

Very similar to HTML except this one will appendChild and only ever receives jQuery collections. If this is overridden on a parent view, it will be used when inserting child views (insertView).

Default:

insert: function($root, $el) {
  $root.append($el);
}

when(promises)

This function will trigger callbacks based on the success/failure of one or more deferred objects.

when: function(promises) {
  return $.when.apply(null, promises);
}

renderTemplate(template, context)

Renders a template with the Function or String provided as the template variable. This method may be asynchronous.

Default:

renderTemplate: function(template, context) {
  return template(context);
}

Example:

renderTemplate: function(template, context) {
  // To put this method into async-mode, simply call `async` and store the
  // return value (callback function).
  var done = this.async();

  // Assuming the template function accepts the context object and a callback
  // function, this is how you would render the template.
  template(context, function(contents) {
    done(contents);
  });
}

contains(parent, child)

This method uses jQuery to determine if a child element exists in a parent element. This method will always received DOM Elements as arguments.

Default:

contains: function(parent, child) {
  return $.contains(parent, child);
}