dna

Evolution-based components.

Properties

Properties are source of truth for component state. They differ from DOM attributes because can accept any sort of object (not only strings or numbers) and let DNA to achieve the abstraction it requires for interoperability.

But defining class properties as getters and setters can be redundant just without implementing validation and observers, that are two primary features for building great components.

With the prop helper and PropertiesMixin, DNA can set up a strong property system: during the initialization it will search for properties member in all the prototype chain (so you can inherit properties from super classes or other mixins) and define instance's getters and setters through the prop helper.

// component.js
import { prop, BaseComponent, define } from '@dnajs/idom';

export class MyComponent extends BaseComponent {
    get properties() {
        return {
             firstName: String,
             lastName: prop.STRING,
             age: prop.NUMBER.validate(n => n > 0),
             children: prop.ARRAY.default([]),
             married: prop.BOOLEAN.attribute(),
             role: prop.STRING.default('visitor').observe('onRoleChanged'),
        };
    }

    get fullname() {
        return `${this.firstName} ${this.lastName}`;
    }

    onRoleChanged() {
        // role changed
    }

    propertyChangedCallback(name, oldVal, newVal) {
       // something changed
    }
}

define('my-component', MyComponent);
// index.js
import { MyComponent } from './component.js';

let elem = new MyComponent();
elem.firstName = 'Alan';
elem.lastName = 'Turing';
console.log(elem.fullname);
// --> "Alan Turing"

propertyChangedCallback

PropertiesMixin extends the list of native callbacks with the propertyChangedCallback, similar to the attributeChangedCallback. It is a sort of "component state updated", in fact the TemplateMixin use this callback to trigger a re-render.

Property definition

The prop helper instantiate a private Property class with some methods for definition. All methods return the instance, so a definition chain can be built.

prop([String, Number])                     // prop helper param is a constructor or a list of constructor for value validation
    .named('prop')                         // define the property name
    .validate((val) => val})               // define a custom validation property
    .default(2)                            // define a default value for the property
    .attribute('data-prop')                // define an attribute to sync (blank: the property name)
    .observe((prop, oldVal, newVal) => {}) // define an observer for the property
    .dispatch('prop-changed')              // define a DOM event to trigger on property changed
    .getter((prop) => prop.value)          // define a custom getter
    .setter((val) => val)                  // define a custom setter

On creation, DNA auto set the property name using the relative key in the properties getter.

Also note that the attribute configuration is automatically invoked when the property name is in the static observedAttributes list.