Friday, December 18, 2015

Aurelia - Initializing properties in custom elements

I'm working on wrapping a couple of external controls into Aurelia custom elements. I'm nearly done, and about to put them out onto Github. In my initial implementation, I only exposed the capabilities of the underlying control that I was going to use, but now that I'm about to push them into the public, I thought I should probably make some effort at exposing a bit more.

In one case, I have a control that offers about 20 properties that can be configured, but in reality, most will be set only at initialization, so I decided as a first pass to make them one-time, initialization-only properties. But I didn't want to clutter my component with 20 properties, so an init property seemed the best solution (thanks, BTW, to @stoffeastrom for his help on getting the syntax right). Here's what I ended up with.

In the view model, I have:

import {inject, bindingMode, bindable} from 'aurelia-framework';

@bindable ({
    name: 'init', 
    defaultBindingMode: bindingMode.oneTime
})
@inject(Element)
export class MyElementCustomElement {
    constructor(element, bindingEngine) {
        this.element = element;
    }

    bind() {
        let init = {};
        if (this.init) {
            Object.assign(init, this.init);
        }

        // Use init to initialize the underlying control
    }
}

Then, when I use the custom element, I write:

<my-element init.bind="{size: 'small', onText: 'Readonly', offText: 'Editable'}"></my-element>

The properties size, onText and offText are properties of the underlying control.

One thing that caught me was the use of init.bind, rather than just init. When you have a bindable property on a custom element, but you want to bind it to a static string, you don't use .bind. Since my first thought was that the set of initial properties was a static entity, I didn't need .bind. Wrong. I want Aurelia's binding engine to parse the property into an object for me so that I can use it to initialize the underlying control. Thus, I have to use .bind, even though the property is not bound to my view model.

Again, is there anything I want to do that Aurelia won't help me with?

No comments: