This README describes a new feature proposal to ECMASCRIPT.
The feature consists of a browser API that handles custom html attributes.
Custom html attributes, are aimed to fill some cases that are not handled by custom elements. It consists of adding reusable attributes that can be set to any html element.
Custom attributes should have a special notation (eg: starting by #
), to distinguish them from normal attributes.
Defining a new custom attribute is made using a define
function of customAttributes
API. (like custom elements)
The define
function takes two arguments, the attribute name and settings.
The second argument (settings
) is an object with three properties, each one is a function:
- connectedCallback: run when the element is connected to DOM (at the same time of connectedCallback of custom element). Takes 2 args (
value
,element
) - addedCallback: run when the attribute is added to an element. Takes 2 args (
value
,element
) - changedCallback: run when the attribute is changed. Takes 2 args (
oldValue
,newValue
,element
) - removedCallback: run when the attribute is removed from an element. Takes 2 args (
oldValue
,element
)
Let's suppose we want to make all form elements change their value on a certain event. Using custom elements we would, in the best way, create a custom element that extends every form element, and then call the wanted behaviour into every class we created. It would look like this: HTML:
<input is="custom-input" set-value-on="updateValues" name="name"/>
<output is="custom-output" set-value-on="updateValues" name="age"/>
<select name="city" set-value-on="updateValues" is="custom-select">
<option>Sousse</option>
<option>Makkah</option>
<option>New York</option>
<option>Tokyo</option>
...
</select>
<textarea is="custom-area" set-value-on="updateValues" name="description"></textarea>
Create the listener in a separate file, let's call it listener.js
, with this content:
export default element => ({detail}) => {
element.value = detail[element.name];
}
Then create custom-input.js
with this content:
import listener from "listener";
class CustomInput extends HTMLInputElement {
constructor() {
super();
this.listener = listener(this);
this.eventName = this.getAttribute("set-value-on");
}
connectedCallback() {
document.addEventListener(this.eventName, this.listener)
}
disconnectedCallback() {
document.removeEventListener(this.eventName, this.listener)
}
}
customElements.define('element-details', CustomInput);
And do that for every form element output
select
textarea
HTML:
<input #set-value-on="updateValues" name="name"/>
<output #set-value-on="updateValues" name="age"/>
<select name="city" #set-value-on="updateValues">
<option>Sousse</option>
<option>Makkah</option>
<option>New York</option>
<option>Tokyo</option>
...
</select>
<textarea #set-value-on="updateValues" name="description"></textarea>
Javascript:
const listener = element => ({ detail }) => {
element.value = detail[element.name];
};
let elementListener;
const connectedCallback = (eventName, element) => {
elementListener = listener(element);
document.addEventListener(eventName, elementListener);
}
const addedCallback = connectedCallback;
const removedCallback = (oldEventName, element) => {
document.removeEventListener(oldEventName, elementListener);
}
const changedCallback = (oldEventName, newEventName, element) => {
removedCallback(oldEventName, element);
connectedCallback(newEventName, element);
}
customAttributes.define("#set-value-on", { connectedCallback, addedCallback, changedCallback, removedCallback })