Partials

edit this page

A partial is a template snippet which can be inserted into templates, or indeed other partials. They help to keep templates uncluttered and easy to read. In this example, we're creating a {{>thumbnail}} partial:

<!-- the main template -->
<div class='gallery'>
  {{#items}}
    {{>thumbnail}}
  {{/items}}
</div>
<!-- the partial -->
<figure class='thumbnail'>
  <img src='assets/thumbnails/{{id}}.jpg'>
  <figcaption>{{description}}</figcaption>
</figure>

Creating partials

There are several ways to use partials.

As an initialisation option

You can specify partials when you create a Ractive instance:

ractive = new Ractive({
  el: myContainer,
  template: myTemplate,
  partials: { thumbnail: myThumbnailPartial },
  data: { items: myItems }
});

Here, myThumbnailPartial can be a string template or a parsed template.

As a globally available partial

Equally, you can make partials globally available by adding them to Ractive.partials:

Ractive.partials.thumbnail = myThumbnailPartial;

Again, this can be a string template or parsed template - if a string, it will be parsed when it first gets used and stored as a parsed template thereafter.

As a script tag

This method is particularly convenient if you don't want to load templates via AJAX:

<script id='thumbnail' type='text/ractive'>
  <figure class='thumbnail'>
    <img src='assets/thumbnails/{{id}}.jpg'>
    <figcaption>{{description}}</figcaption>
  </figure>
</script>

The type attribute isn't important, as long as it exists and isn't text/javascript. All that matters is that it's a script tag whose id attribute matches the name of the partial. It's fairly common to see Ractive templates in script tags with type="text/ractive" to clearly indicate that they are meant to be handled by Ractive. It can be useful, though, to specify type="text/html" since many text editors support HTML templates in script tags for templating purposes.

Internally, when a template requests the {{>thumbnail}} partial, Ractive will look for it on ractive.partials, then Ractive.partials, and if both of those fail it will then look for an element with an id of thumbnail. If it exists, it will parse its content and store it on Ractive.partials, to make subsequent lookups quicker.

Inline partials

It is also possible to embed partials within templates. Suppose you have a single mainTemplate.html file. You can define any partials within it by wrapping them in comments that follow this structure:

<div class='gallery'>
  {{#items}}
    {{>thumbnail}}
  {{/items}}
</div>

<!-- {{>thumbnail}} -->
<figure class='thumbnail'>
  <img src='assets/thumbnails/{{id}}.jpg'>
  <figcaption>{{description}}</figcaption>
</figure>
<!-- {{/thumbnail}} -->

In this case, the thumbnail partial won't be globally available - it will only be available to Ractive instances that use this template.

Partial expressions

Partial references may be a name that already exists as a partial, or they may also be any expression that resolves to a partial name. This can be used to select an appropriate partial based on the current context and more. The full power of Ractive's expressions are available. If the value of the expression changes, the partial fragment will be re-rendered using the new partial.

If a partial expression is a simple reference and a partial exists with the same name as the reference, the expression will not be evaluated. Instead, the partial with the same name as the reference will be used. For instance, if there are partials named foo and bar, a data member foo: 'bar', and a partial section {{>foo}}, the partial named foo will be used for the section because name-matching takes precedent over expression evaluation.

Example: Item specialization

{{#list}}{{>.type}}{{/}}

<!-- {{>person}} -->
  {{.name}} is a person. {{.pronoun}} has {{.fingerCount}} fingers.
<!-- {{/person}} -->

<!-- {{>animal}} -->
  {{.name}} is a {{.specie}}. {{.pronoun}} has {{.legCount}} legs.
<!-- {{/animal}} -->

This example uses a combination of patial expressions and restricted references in the iteration of list to render a different template based on the type of item in the list. If there was an item { type: 'person', name: 'John', pronoun: 'He', fingerCount: 9 } in the list, its output would be John is a person. He has 9 fingers.. { type: 'animal', name: 'Alfred', specie: 'starfish', pronoun: 'It', legCount: 5 } would output Alfred is a starfish. It has 5 legs..

Example: Partials on-the-fly

<script id="template" type="text/ractive">
  Add a partial: <textarea value="{{tpl}}" /><button on-click="add()">Add</button><br/>
  {{#list}}{{>makePartial(.id, .template)}}{{/}}
</script>
new Ractive({
  template: '#template',
  el: 'main',
  data: {
    list: [],
    tpl: '',
    makePartial: function(id, template) {
      var key = 'partial-' + id;
      if (!!this.partials[key]) return key;
      this.partials[key] = template;
      return key;
    }
  },
  add: function() {
    this.push('list', { id: Math.random(), template: this.get('tpl') });
    this.set('tpl', '');
  }
});

This example uses a function to generate a partial on-the-fly and return the new generated partial name to be rendered. Note that if the template value for any of the items in list changes, its corresponding partial will not be updated in this instance. If you need to achieve something like that, you could modify the function to wrap the partial content in a conditional and modify the cacheing logic to re-render the target partial when its template changed.

Invalid names

Since the partial name may be an expression, JavaScript keywords cannot be used in partial expressions. This means that {{>delete}} is not valid. Keywords and other otherwise-invalid names may be used with a string expression such as {{>'delete'}} or {{>'invalid-name here'}}.

Partial context

Partial sections may be given explicit context by adding an expression after the name in the form of {{>[name expression] [context expression]}}. The partial will then be executed with the given context instead of the context in which the partial section appears. This has the same effect as wrapping the partial section in a #with section.

{{#list}}{{>somePartial { item: ., magicNumber: 42 }}}{{/}}

In this example, {{item}} in somePartial will resolve to the current item in list and magicNumber will resolve to 42. Ancestor references, members, object literals, and any other expressions that resolve to an object may be used as a context expression.

Recursive partials

Partials can be used recursively:

<div class='fileSystem'>
  {{#root}}
    {{>folder}}
  {{/root}}
</div>

<!-- {{>folder}} -->
<ul class='folder'>
  {{#files}}
    {{>file}}
  {{/files}}
</ul>
<!-- {{/folder}} -->

<!-- {{>file}} -->
<li class='file'>
  <img class='icon-{{type}}'>
  <span>{{filename}}</span>

  <!-- if this is actually a folder, embed the folder partial -->
  {{# type === 'folder' }}
    {{>folder}}
  {{/ type === 'folder' }}
</li>
<!-- {{/file}} -->
rv = new Ractive({
  el: 'container',
  template: '#myTemplate',
  data: {
    root: {
      files: [
        { type: 'jpg', filename: 'hello.jpg' },
        { type: 'mp3', filename: 'NeverGonna.mp3' },
        { type: 'folder', filename: 'subfolder', files: [
          { type: 'txt', filename: 'README.txt' },
          { type: 'folder', filename: 'rabbithole', files: [
            { type: 'txt', filename: 'Inception.txt' }
          ]}
        ]}
      ]
    }
  }
});

In the example above, subfolders use the {{>folder}} partial, which uses the {{>file}} partial for each file, and if any of those files are folders, the {{>folder}} partial will be invoked again, and so on until there are no more files.

Beware of cyclical data structures! Ractive makes no attempt to detect cyclicality, and will happily continue rendering partials until the Big Crunch (or your browser exceeds its maximum call stack size. Whichever is sooner).

Injecting partials

One good use of partials is to vary the shape of a template according to some condition, the same way you might use dependency injection elsewhere in your code.

For example, you might offer a different view to mobile users:

<div class='main'>
  <div class='content'>
    {{>content}}
  </div>

  <div class='sidebar'>
    {{>sidebar}}
  </div>
</div>
isMobile = /mobile/i.test( navigator.userAgent ); // please don't do this in real life!

ractive = new Ractive({
  el: myContainer,
  template: myTemplate,
  partials: {
    content: isMobile ? mobileContentPartial : desktopContentPartial,
    sidebar: isMobile ? mobileSidebarPartial : desktopSidebarPartial
  }
});

Or you might make it possible to extend a subclass without overriding its template:

<div class='modal-background'>
  <div class='modal'>
    {{>modalContent}}
  </div>
</div>
// Create a Modal subclass
Modal = Ractive.extend({
  template: modalTemplate,
  init: function () {
    var self = this, resizeHandler;

    resizeHandler = function () {
      self.center();
    };

    // when the window resizes, keep the modal horizontally and vertically centred
    window.addEventListener( 'resize', resizeHandler );

    // clean up after ourselves later
    this.on( 'teardown', function () {
      window.removeEventListener( 'resize', resizeHandler );
    });

    // manually call this.center() the first time
    this.center();
  },
  center: function () {
    // centering logic goes here
  }
});

helloModal = new Modal({
  el: document.body,
  partials: {
    modalContent: '<p>Hello!</p><a class="modal-button" proxy-tap="close">Close</a>'
  }
});

helloModal.on( 'close', function () {
  this.teardown();
});

Updating Partials

Partials may be updated after they are rendered if they are held within a conditional section. They will be re-parsed each time they are re-rendered, if necessary, so string, pre-parsed, and function partials may be used.

{{^toggle}}{{>rickroll}}{{/}}
ractive.partials.rickroll = 'I wouldn\'t do that to you, chum.';
ractive.set('toggle', true);
ractive.set('toggle', false);

This is a little hacky, but it brings an element of dynamism that can be very useful.