I'm trying to make a control allowing the user to set a value both through a numeric input and through a slider. Having read the relevant docs, this is what I came with:
class NumberAndRange extends HTMLElement {
constructor() {
super()
const shadow = this.attachShadow({mode: 'open'})
this.number = document.createElement('input')
this.number.type = 'number'
this.range = document.createElement('input')
this.range.type = 'range'
this.number.addEventListener('input',
()=>{this.range.value = this.number.value}
)
this.range.addEventListener('input',
()=>{this.number.value = this.range.value}
)
shadow.appendChild(this.number)
shadow.appendChild(this.range)
}
}
customElements.define('number-and-range', NumberAndRange)
<number-and-range></number-and-range>
As you can see, it works (at least in browsers that support this). For brevity, I skipped the code that makes sure that setting the min, max, step etc attributes on numeric-and-range also sets them on both inputs and that reading these attributes from numeric-and-range returns meaningful results.
However, there is one functionality I'm not able to add. Clearly, we would like that triggering an input event on both numeric and range would also trigger this event on numeric-and-range; so that we may forget that numeric-and-range actually consists of two inputs and instead treat it as if it was a single control. Therefore:
class NumberAndRange extends HTMLElement {
constructor() {
super()
const shadow = this.attachShadow({mode: 'open'})
this.number = document.createElement('input')
this.number.type = 'number'
this.range = document.createElement('input')
this.range.type = 'range'
this.number.addEventListener('input',
()=>{this.range.value = this.number.value}
)
this.range.addEventListener('input',
()=>{this.number.value = this.range.value}
)
const whole = this
this.number.addEventListener('input',
(ev)=>{whole.dispatchEvent(ev)}
)
this.range.addEventListener('input',
(ev)=>{whole.dispatchEvent(ev)}
)
shadow.appendChild(this.number)
shadow.appendChild(this.range)
}
}
customElements.define('number-and-range', NumberAndRange)
<number-and-range></number-and-range>
But this doesn't work! For reasons beyond my coprehension moving the slider throws. InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable Which object is not usable? And why would it not be usable? I'm staring at my code and can't really find any mistake.
Could you enlighten me what am I doing wrong?
Edit: The idea suggested in the comments doesn't seem to work for me either:
class NumberAndRange extends HTMLElement {
connectedCallback() {
const whole = this
this.number.addEventListener('input',
(ev)=>{whole.dispatchEvent(ev)}
)
this.range.addEventListener('input',
(ev)=>{whole.dispatchEvent(ev)}
)
}
constructor() {
super()
const shadow = this.attachShadow({mode: 'open'})
this.number = document.createElement('input')
this.number.type = 'numeric'
this.range = document.createElement('input')
this.range.type = 'range'
this.number.addEventListener('input',
()=>{this.range.value = this.number.value}
)
this.range.addEventListener('input',
()=>{this.number.value = this.range.value}
)
shadow.appendChild(this.number)
shadow.appendChild(this.range)
}
}
customElements.define('number-and-range', NumberAndRange)
<number-and-range></number-and-range>