Array modification

edit this page

By default, Ractive will intercept the mutator methods (pop, push, shift, unshift, splice, sort and reverse) of arrays that it depends on for more convenient data binding.

Consider the following:

<ul>
  {{#list}}
    <li>[object Object]</li>
  {{/list}}
</ul>
list = [ 'a', 'b', 'c' ];

ractive = new Ractive({
  el: myContainer,
  template: myTemplate,
  data: { list: list }
});

list.push( 'd' ); // adds a new list item - <li>d</li>

You can disable this behaviour by passing in modifyArrays: false as an initialisation Options

How it works

Don't worry, we're not modifying Array.prototype. (What do you think this is, Ember? :-)

Instead, we're using a technique called prototype chain injection, which allows us to remain performant and memory-efficient without mucking about extending native objects.

This uses the non-standard (but very unlikely to disappear!) __proto__ property. That might seem kludgy, but if Mike Bostock thinks it's okay then that's good enough for us.

Older browsers (I'm looking at you, IE8) don't support __proto__ - in these cases, we simply add the wrapped methods as properties of the array itself.

As well as intercepting or wrapping the mutator methods, Ractive adds a (non-enumerable, in modern browsers) _ractive property to arrays, which contains information about which Ractive instances depend on the array, and which keypaths it is assigned to.

Hygiene

When an array is no longer depended on by any Ractive instances, we can revert it to its normal state - resetting its prototype (if we used prototype chain injection) or deleting the wrapped methods (if we're in a crap browser), and removing the _ractive property.

Performance and UI benefits

As well as convenience, using arrays like this helps Ractive make smart decisions about how to update the DOM. Continuing the example above, compare these two alternative methods of inserting a new item at the start of our list:

// at the moment, list = [ 'a', 'b', 'c', 'd' ]

// 1. Reset the list:
ractive.set( 'list', [ 'z', 'a', 'b', 'c', 'd' ] )

// 2. Use `unshift`:
list.unshift( 'z' );

In the first example, Ractive will see that the content of the first list item has changed from 'a' to 'z', and that the second has changed from 'b' to 'a', and so on, and update the DOM accordingly. It will also see that there is now a fifth item, so will append <li>d</li> to the list.

In the second example, Ractive will understand that all it needs to do is insert <li>z</li> at the start of the list, leaving everything else untouched.

This is particularly important if you're using transitions, as it will be obvious to the user which elements are being added and removed.

Note that if list.unshift('z') isn't an option, you could use ractive.merge() to achieve the same effect.