From a4a9f85956792ec8f6d2500a8b6bf16b612801a0 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Wed, 12 Jun 2024 15:43:09 +0200 Subject: [PATCH] Dynamic tables: focus to first input when adding a row. --- .../common/lib/elements/dynamic-table-form.ts | 13 ++++++++++++- client/common/lib/elements/tags-input.ts | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/client/common/lib/elements/dynamic-table-form.ts b/client/common/lib/elements/dynamic-table-form.ts index 31d2c1c0..6202ca78 100644 --- a/client/common/lib/elements/dynamic-table-form.ts +++ b/client/common/lib/elements/dynamic-table-form.ts @@ -140,7 +140,7 @@ export class DynamicTableFormElement extends LivechatElement { return Object.fromEntries([...Object.entries(this.schema).map((entry) => [entry[0], entry[1].default ?? ''])]) } - private readonly _addRow = (): void => { + private async _addRow (): Promise { const newRow = this._getDefaultRow() // Create row and assign id and original index this._rowsById.push({ _id: this._lastRowId++, _originalIndex: this.rows.length, row: newRow }) @@ -148,6 +148,17 @@ export class DynamicTableFormElement extends LivechatElement { this.requestUpdate('rows') this.requestUpdate('_rowsById') this.dispatchEvent(new CustomEvent('update', { detail: this.rows })) + + // Once the update is completed, we give focus to the first input field of the new row. + await this.updateComplete + // Note: we make multiple querySelector, to be sure to not get a nested table. + // We want the top level table associated tr. + const input = this.querySelector('table')?.querySelector( + '&>tbody>tr:last-child>td input:not([type=hidden]),&>tbody>tr:last-child>td livechat-tags-input' + ) + if (input) { + (input as HTMLElement).focus() + } } private async _removeRow (rowId: number): Promise { diff --git a/client/common/lib/elements/tags-input.ts b/client/common/lib/elements/tags-input.ts index 833f97cc..84d6291b 100644 --- a/client/common/lib/elements/tags-input.ts +++ b/client/common/lib/elements/tags-input.ts @@ -54,6 +54,25 @@ export class TagsInputElement extends LivechatElement { @property({ attribute: false }) public animDuration: number = 200 + /** + * Overloading the standard focus method. + */ + public override focus (): void { + const input = this.querySelector('input[type=text]') + if (input) { + (input as HTMLInputElement).focus() + return + } + // Never rendered, we will wait for the update to be complete, and then render. + // This is not fully compliant, as it is not synchrone... But needed (see dynamic-table addRow) + this.updateComplete.then(() => { + const input = this.querySelector('input[type=text]') + if (input) { + (input as HTMLInputElement).focus() + } + }, () => {}) + } + protected override render = (): unknown => { return html`