I have a bug in an application using lit-element custom web-components: When manually editing a HTML Input element, changes in the internal component state are no longer reflected in that element. However, before doing any manual edits, the values are correctly reflected.
I seem to miss some knowledge on how HTML element attributes work. Either that, or I lack knowledge around lit-element.
My suspicion is on the way the DOM node works in detail. But I may be wrong. It seems that as soon as a manual edit it made to the "Input" element, its behaviour changes and it always keeps the user-value, even if something else changes. Conversely though, getting a reference to the input-element in the dev-tools console (via right-click, inspect and then using the $0
variable) allows me to do $0.value = 'foo'
and the value 'foo' will be displayed in the field.
So with that last experiment I am not so sure anymore. Has it something to do with lit
after all? I'm all out of ideas...
It seems to be a very common thing to do so I would assume that lit
should support this, and that I'm doing something wrong somewhere...
I could listen to change events and then set the .value
propery manually. But that seems unnecessarily "manual". So how do I do this correctly?
I managed to reduce the issue to a really small reproducible example. I wrote it up on codepen here: https://codepen.io/exhuma/pen/eYrNQJK
For reference, here's the code using and defining the component:
<!-- using the component -->
<text-field-demo></text-field-demo>
<script type="module" src="path-to-ts-file" />
// The TypeScript file to load in the HTML
// document which uses the component
import {
LitElement,
html,
customElement,
state
} from "https://cdn.skypack.dev/lit@2.3.1";
export class TextFieldDemo extends LitElement {
// [does not work in CodePen] @state()
data = 0;
doIncrement() {
// This increment should be reflected in the UI
// even *after* a manual edit was made in
// the text-field
this.data += 1;
console.log(this.data);
this.requestUpdate();
}
/**
* Update the local component state with the new value from the DOM
* @param evt The change event
*/
updateObject(evt) {
this.data = Number.parseInt(evt.target.value, 10);
}
render() {
return html`
Object:
<input type="text" value=${this.data} @change=${this.updateObject} />
<button @click=${this.doIncrement}>Increment and log</button>
<pre>Data in non-interactive element: ${this.data}</pre>
`;
}
}
customElements.define("text-field-demo", TextFieldDemo);