A <message-input> Web Component
The example still uses plain JavaScript to listen to input events
and to update the message. This post replaces the original <label> and <input> element with a new component.
The sources to this web component and others can be found on GitHub: https://github.com/bvfnbk/example-web-components
The component gets defined in src/ts/MessageInput.ts and its template basically replaces the original elements
<label for="someInput">Message:</label>
<input id="someInput" type="text"/>
and implicitly handles the input event on the <input> element. The most important changes are:
const messageInputTemplate: HTMLTemplateElement = document.createElement('template');
messageInputTemplate.innerHTML = `
<div>
<label for="someInput">Message:</label>
<input id="someInput" type="text"/>
</div>
`;
class MessageInput extends HTMLElement {
private shadow: ShadowRoot;
private inputElement: HTMLInputElement;
private readonly eventHandler: EventListener;
constructor() {
super();
this.shadow = this.attachShadow({mode: 'open'});
this.shadow.appendChild(messageInputTemplate.content.cloneNode(true));
this.inputElement = this.shadow.getElementById('someInput')! as HTMLInputElement;
this.eventHandler = (event: Event) => this.inputEventHandler(event as InputEvent);
}
connectedCallback() {
this.inputElement.addEventListener('input', this.eventHandler);
}
disconnectedCallback() {
this.inputElement.removeEventListener('input', this.eventHandler);
}
private inputEventHandler(inputEvent: InputEvent) {
inputEvent.stopPropagation();
this.dispatchEvent(new CustomEvent<string>(
'MessageUpdateEvent',
{detail: this.inputElement.value}
));
}
}
The characteristics of this component are quickly summarized:
- The concrete event handler (
eventHandler: EventListener) is added in theconnectedCallbacklifecycle method and cleaned up in thedisconnectedCallback. - The actual input event handler stops the event propagation; otherwise, the
inputevent would continue upwards. - A new, custom event is being dispatched with the input value as
details. The parent may then add a listener forMessageUpdateEventevents. - The test specification in
src/test/MessageInput.spec.tsasserts the proper event handling.