I'm trying to learn StencilJs and have created an "editable text" Component like this.
import { Component, h, Prop, Element } from '@stencil/core';
@Component({
tag: 'app-input',
styleUrl: 'app-input.scss',
shadow: true,
})
export class AppInput {
@Element() el: HTMLElement;
@Prop() editMode = false;
@Prop() value: string;
private textInput: HTMLInputElement;
private label: HTMLDivElement;
componentDidUpdate() {
if (this.textInput) {
this.textInput.focus();
} else {
this.label.focus();
}
}
eventHandler(event: KeyboardEvent | FocusEvent): void {
if (event instanceof KeyboardEvent) {
if (this.editMode) {
if (event.code === 'Enter') {
this.value = (event.target as HTMLInputElement).value;
this.editMode = false;
} else if (event.code === 'Escape') {
this.editMode = false;
}
} else {
if (['Space', 'Enter'].some(key => key === event.code)) {
this.editMode = true;
}
}
} else if (event instanceof FocusEvent) {
this.editMode = false;
}
}
render() {
if (this.editMode) {
return (
<div>
<input
type="text"
ref={el => this.textInput = el as HTMLInputElement}
value={ this.value }
onKeyDown={(event) => this.eventHandler(event)}
onBlur={(event) => this.eventHandler(event)}></input>
</div>
)
} else {
return (
<div
tabindex="0"
ref={el => this.label = el as HTMLDivElement}
onKeyDown={(event) => this.eventHandler(event)}
onClick={() => this.editMode = true} >{ this.value }</div>
);
}
}
}
The problem is that if a parent component updates then so does this and componentDidUpdate
runs, setting focus when it shouldn't. Is there a way I can tell (maybe by custom decorators) componentDidUpdate to only run if the update was triggered from within this component? Or is there another way to go about it?