Is there a way to two-way bind an attribute of a custom HTML element in Blazor? I have a custom element with a value attribute linked to a text input internally that I'd like to bind the value of.
<template id="text">
<div style="height:40px; width:100%; display:flex; flex-direction:column; justify-content:center; align-items:flex-start; padding:10px">
<label for="textline" style="padding-left:5px"><slot name="label"></slot></label>
<input type="text" id="textline" style="border:solid 2px lightgrey; border-radius:5px; padding:5px; font-family:Montserrat; height:100%; font-size:15px; width:100%; box-sizing: border-box;" />
</div>
</template>
Here's the JS defining the custom element:
customElements.define(
"bonsai-text-box",
class extends HTMLElement {
static observedAttributes = ["label", "value"];
constructor() {
super();
}
async connectedCallback() {
let html = await fetch("https://nexusdockapidev.ctdi.com/GetBonsaiHTML");
let json = await html.json();
let div = document.createElement('div');
div.innerHTML = json.html;
this.appendChild(div);
let template = document.getElementById("text");
let templateContent = template.content;
const label = this.getAttribute("label");
const labelSpan = document.createElement("span");
labelSpan.setAttribute("slot", "label");
labelSpan.setAttribute("id", "labelspan");
labelSpan.innerHTML = label;
const shadowRoot = this.attachShadow({ mode: "open" });
let css = await fetch("https://nexusdockapidev.ctdi.com/GetBonsaiCSS");
let cssjson = await css.json();
let style = document.createElement('style');
style.innerHTML = cssjson.css;
shadowRoot.appendChild(style);
shadowRoot.appendChild(templateContent.cloneNode(true));
this.appendChild(labelSpan);
this.inputNode = this.shadowRoot.querySelector('input')
this.inputNode.addEventListener("change", (e) => {
this.setAttribute("value", e.target.value);
});
}
get value () {
return this.inputNode.value
}
set value (newValue) {
this.inputNode.value = newValue
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === "label") {
const oldlabelspan = this.querySelector("#labelspan");
if (oldlabelspan) {
oldlabelspan.parentNode.removeChild(oldlabelspan);
const labelSpan = document.createElement("span");
labelSpan.setAttribute("slot", "label");
labelSpan.setAttribute("id", "labelspan");
labelSpan.innerHTML = newValue;
this.appendChild(labelSpan);
this.dispatchEvent(new Event("change"));
}
}
else if (name === 'value') {
this.inputNode.value = newValue;
}
}
},
);
I've tried @bind and @bind-value and neither seem to work how I expect.