Reputation: 333
I try to create my own custom DOM elements with Web Components (with validation and server communication). I am following the tutorial on the MDN: https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements
attributeChangedCallback(name, oldValue, newValue) {
console.log(newValue);
}
I am able to receive the change of an attribute. But if I have for example a textbox, where the value gets changed. How do I bind the value of the textbox to the attribute? Is this even a good way to do it?
This is my code:
'use strict';
class PopUpInfo extends HTMLElement {
static get observedAttributes() {
return ['value'];
}
constructor() {
// Always call super first in constructor
super();
// write element functionality in here
var shadow = this.attachShadow({mode: 'closed'});
console.log("Created");
let tbName = document.createElement("input");
shadow.appendChild(tbName);
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(newValue);
}
}
customElements.define('popup-info', PopUpInfo);
Later on, I would like to add multiple html controls to "PopUpInfo". The name would be later somthing like "Controlunit".
Upvotes: 3
Views: 1616
Reputation: 10945
You need to take the attribute, or a property and pass that value into the inner DOM. There is no "binding" unless you are using a framework. If you want to use LitElement or other things then you get binding. Personally I see those frameworks as a huge amount of overhead.
But look at this example:
class PopUpInfo extends HTMLElement {
static get observedAttributes() {
return ['value'];
}
constructor() {
// Always call super first in constructor
super();
// write element functionality in here
var shadow = this.attachShadow({mode: 'open'});
let textEl = document.createElement("input");
shadow.appendChild(textEl);
// Set attribute to value of inner element `.value`
textEl.addEventListener('input', (evt) => {
this.setAttribute('value', textEl.value);
});
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(`attributeChangedCallback(${name}, ${oldValue}, ${newValue})`);
if (oldValue !== newValue) {
this.value = newValue;
}
}
get value() {
let textEl = this.shadowRoot.querySelector("input");
return textEl.value;
}
set value(newValue) {
console.log(`set value(${newValue})`);
let textEl = this.shadowRoot.querySelector("input");
if (newValue == null) { // check for null and undefined textEl.value = '';
}
else {
textEl.value = newValue;
}
}
}
customElements.define('popup-info', PopUpInfo);
<popup-info value="my info"></popup-info>
First: Since you are only watching one attribute your attributeChangedCallback
function only needs to see if oldValue
and newValue
are different. If they are not different then there is nothing to do. If they are different they you use newValue
.
In my example I am passing the attribute's value on to the property called value
.
In the property setter I check to see if the value is null
or undefined
(Using double equals for null
(x == null
) does just that. If it is null
or undefined
then we set value
of the inner <input>
element to an empty string. If it is not null
or undefined
then we set value
of the inner <input>
element to whatever was sent in.
The property getter just reads the value
of the inner <input>
element and returns that.
Upvotes: 3