From 66d263f81b33d0033726043570bb9867aa80b47f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 19 Mar 2026 18:09:17 +0200 Subject: [PATCH] UI: Fix string-items-list autocomplete selection and blur handling Replace addOnBlur with matChipInputAddOnBlur directive and dedicated onOptionSelected handler for proper autocomplete behavior. Prevent mousedown default on options to avoid premature blur, and conditionally hide "not found" when user values are allowed. --- .../string-items-list.component.html | 11 +++-- .../components/string-items-list.component.ts | 45 ++++++++++--------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/ui-ngx/src/app/shared/components/string-items-list.component.html b/ui-ngx/src/app/shared/components/string-items-list.component.html index 7a0ac10e83..7a0489345f 100644 --- a/ui-ngx/src/app/shared/components/string-items-list.component.html +++ b/ui-ngx/src/app/shared/components/string-items-list.component.html @@ -31,7 +31,6 @@ close + [matAutocompleteDisabled]="!predefinedValues?.length && !fetchOptionsFn"> @for (value of filteredValues | async; track value.value) { - + } @empty { - {{ 'common.not-found' | translate }} + @if (!allowUserValue) { + {{ 'common.not-found' | translate }} + } } diff --git a/ui-ngx/src/app/shared/components/string-items-list.component.ts b/ui-ngx/src/app/shared/components/string-items-list.component.ts index 4f9f9cc178..fe9c2746c3 100644 --- a/ui-ngx/src/app/shared/components/string-items-list.component.ts +++ b/ui-ngx/src/app/shared/components/string-items-list.component.ts @@ -29,7 +29,7 @@ import { FloatLabelType, MatFormFieldAppearance, SubscriptSizing } from '@angula import { coerceArray, coerceBoolean } from '@shared/decorators/coercion'; import { Observable, of } from 'rxjs'; import { filter, mergeMap, share, tap } from 'rxjs/operators'; -import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; +import { MatAutocompleteSelectedEvent, MatAutocompleteTrigger } from '@angular/material/autocomplete'; import { isDefined, isUndefined } from '@core/utils'; export interface StringItemsOption { @@ -37,18 +37,18 @@ export interface StringItemsOption { value: any; } @Component({ - selector: 'tb-string-items-list', - templateUrl: './string-items-list.component.html', - styleUrls: [], - providers: [ - { - provide: NG_VALUE_ACCESSOR, - useExisting: forwardRef(() => StringItemsListComponent), - multi: true - } - ], - encapsulation: ViewEncapsulation.None, - standalone: false + selector: 'tb-string-items-list', + templateUrl: './string-items-list.component.html', + styleUrls: [], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => StringItemsListComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None, + standalone: false }) export class StringItemsListComponent implements ControlValueAccessor, OnInit { @@ -149,9 +149,7 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit { this.filteredValues = this.itemControl.valueChanges .pipe( tap((value) => { - if (value && typeof value !== 'string') { - this.add(value); - } else if (value === null) { + if (value === null) { this.clear(); } }), @@ -209,16 +207,17 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit { this.dirty = true; } - addOnBlur(event: FocusEvent) { - const target: HTMLElement = event.relatedTarget as HTMLElement; - if (target && target.tagName !== 'MAT-OPTION') { - this.addItem(this.stringItemInput.nativeElement.value ?? '') + onOptionSelected(event: MatAutocompleteSelectedEvent): void { + if (event.option.value) { + this.add(event.option.value); + } else { + this.clear(); } - this.onTouched(); } addOnEnd(event: MatChipInputEvent): void { - this.addItem(event.value ?? '') + this.addItem(event.value ?? ''); + this.onTouched(); } removeItems(item: StringItemsOption) { @@ -295,6 +294,8 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit { this.stringItemInput.nativeElement.value = value; this.itemControl.patchValue(value, {emitEvent: true}); setTimeout(() => { + this.stringItemInput.nativeElement.value = value; + this.itemControl.patchValue(null, {emitEvent: false}); this.stringItemInput.nativeElement.blur(); this.stringItemInput.nativeElement.focus(); }, 0);