The toElement Method

Classes like Calendar, Slider, AutoCompleter etc. are all containing elements or responsible for elements.

There are several approaches for how to handle the element in the class:

  • Pass a container element as an argument to the constructor of the class, and append to it new elements that the class creates
  • Have the actual behavior-less element(s) on the HTML and pass them to the class constructor as an argument, the class will apply its behaviors on them
  • Create all elements in the class and have them available for appending

Each approach is good for a different situation, but the toElement method is meant mostly for the last one.

Example of a plain class, and how its element is being appended to the document:

1
2
3
4
5
6
7
8
9
10
var AutoCompleter=new Class({
  initialize:function () {
      this.input=new Element("input");
      // autocomplete magic
  }
});

var autoCompleter=new AutoCompleter();

$("container").grab(autoCompleter.input);

This is quite ugly to use the public property input, which its name can be changed someday and then the code breaks. Moreover, in this way, each class declares its own property and this can lead to inconsistency between the property names.

This is where the toElement method comes in handy: it’s a MooTools convention for a method that simply returns the element.

1
2
3
4
5
6
7
8
9
10
11
12
13
var AutoCompleter=new Class({
  initialize:function () {
      this.input=new Element("input");
      // autocomplete magic
  },
  toElement:function () {
      return this.input;
  }
});

var autoCompleter=new AutoCompleter();

$("container").grab(autoCompleter.toElement());

But wait, there’s more: MooTools $ / document.id function knows that if it gets an object that has the toElement method, the method should be invoked and the returned element will be returned out of the document.id function. Luckily, all of the MooTools Element methods use document.id inside them, so, for instance, when grab or adopt are called with any object as an argument, it will be passed thru the document.id function which will translate it to the toElement result. Hence, we can use this:

1
$("container").grab(autoCompleter);

The ToElement Mixin

The ToElement Mixin is supposed to make the toElement method even simpler, and make it lazy-load the element, i.e. create it only when needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var ToElement=new Class({
  ui:{},
  toElement$ensureElement:function () {
      var element=this.toElement$getElement();
      if (!element && this.build) this.build();
  },
  toElement$getElement:function () {
      return (this.ui ? this.ui.element : this.element) || this.element;
  },
  toElement:function () {
      this.toElement$ensureElement();
      return this.toElement$getElement();
  }
});

Usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var AutoCompleter=new Class({
  Implements:[ToElement],
  initialize:function () {
  },
  build:function () {
      this.ui.element=new Element("input");
      // autocomplete magic
  }
});

var autoCompleter=new AutoCompleter();
// element isn't ready yet

// the grab calls document.id which calls toElement, where the element is prepared
$("container").grab(autoCompleter);

First, it adds a ui hash to every class instance. That’s my convention to save elements in classes of this kind. Second, it adds a toElement method, which is responsible of calling the build method if exists, and return this.ui.element or this.element out of the instance.

Benefits are:

  • Lazy load the element - it’ll be created only when the document asks for it
  • ui hash to contain all other elements, and a build method as a simple convention