Decorators

Overview

Decorators are a very powerful yet simple way to hook into altr to add new functionality. Once a decorator has been defined (see below) it can be used to decorate any element in a template.

Decorators provide 5 places in an elements lifecyle that can be hooked into: create, insert, update, remove, and destroy.

Defining

To add a new decorator to altr:

altr.addDecorator('unique-attribute', create)
altr(
    '<div unique-attribute="a.b.c, 5 * 10, 'foo'"></div>'
  , {a: {b: {c: 123}}}
)

function create(el) {
  return {
      insert: function(el) {}
    , update: function(arg1, arg2, argn) {}
    , remove: function(el, done) {setTimeout(done, 500)})
    , destroy: function() {}
  }
}

The first argument is the attribute the decorator will be bound to. Any time an element is created in an altr template that has this attribute the create function will be called with that element.

create(el)

Each time an element with a matching attribute is added to the template this function will be called.

Most elements in altr are initialized when the template is first created. This means that even if the decorated element is initially inside an if tag that is falsy the create function will still be called. This is because altr was written with the understand that the state of a template is likely to change. Because of this, it is good to use an update hook if the decorator has expectations about the current state.

The main exception to the above, is the for tag. For tags create a sub template for each item it its list. A decorator on an element will only be created once for each item, even if there are multiple updates that change that items index in the list. the documentation for the for tag has more details on how uniqueness and presence in a list is determined.

To hook in to the other lifecycle hooks, the create function may return an object with any/all of the below methods.

The create function is called with the altr instance that it is part of as its context.

Decorators should use this.document rather than the global document if they need to, this maintains compatability with node.

update(arg1[, arg2, ...argN])

A decorators attribute value can specify a comma seperated list of expressions to watch. When the the decorator is first create and any time any of the watched values change, the decorators update function is called, with the current values as arguments.

insert(el)

A decorators insert function is called any time its element is inserted into the dom. It receives 1 argument, el. This is the element responsible for the insertion. this is generally either an if tag or a for tag. el may also be null if the entire template is being inserted into a new node.

remove(el, done)

A decorators remove function is called any time its element is inserted into the dom. It receives 2 arguments, el amd done. el is the same as the the first agument for insert. done is a call back that MUST be called once the decorator is ready to be removed. done MAY be called asynchronously, but MUST only be called once.

remove is asynchronus to allow for exit transitions before an element is removed form the dom.

destroy()

destroy is called once the decorators element has been removed from the dom and will not be reinserted. This allows a decorator to clean up any remaining event listeners or other state such as setInterval calls.

Examples

escape HTML

  • {% tab %}
altr.addDecorator('altr-escape', escape)
altr(document.body, {})

function escape(el) {
  var pre = this.document.createElement('pre')

  pre.textContent = el.innerHTML
  el.innerHTML = ''
  el.appendChild(pre)
}
<div altr-raw altr-escape>
  <h1>hello, World!</h1>
</div>

fade out

  • {% tab %}
altr.addDecorator('fade-out', fade)
var template = altr(document.body, {})

document.addEventListener('click', function() {
  template.update({remove: true})
})

function fade(root) {
  return {remove: remove}

  function remove(el, done) {
    var start = new Date

    step()

    function step() {
      var diff = new Date - start

      if(diff > 1000) {
        return done()
      }

      el.style.opacity = 1 - (diff / 1000)
      setTimeout(step, 15)
    }
  }
}
<div altr-if="!remove" fade-out>
  <div>click to fade out!</div>
</div>

2-way binding

still need to write this example

© . All rights reserved.