Browse Source

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.
pull/15273/head
Vladyslav_Prykhodko 6 months ago
parent
commit
66d263f81b
  1. 11
      ui-ngx/src/app/shared/components/string-items-list.component.html
  2. 45
      ui-ngx/src/app/shared/components/string-items-list.component.ts

11
ui-ngx/src/app/shared/components/string-items-list.component.html

@ -31,7 +31,6 @@
<mat-icon matChipRemove *ngIf="!disabled">close</mat-icon>
</mat-chip-row>
<input matInput type="text"
(blur)="addOnBlur($event)"
placeholder="{{ placeholder }}"
style="max-width: 300px;min-width: 250px"
#stringItemInput
@ -40,19 +39,23 @@
#origin="matAutocompleteOrigin"
[matChipInputFor]="itemsChipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
matAutocompleteOrigin
(matChipInputTokenEnd)="addOnEnd($event)"
[matAutocompleteConnectedTo]="origin"
[matAutocomplete]="stringItemAutocomplete"
[matAutocompleteDisabled]="!predefinedValues?.length">
[matAutocompleteDisabled]="!predefinedValues?.length && !fetchOptionsFn">
</mat-chip-grid>
<mat-autocomplete #stringItemAutocomplete="matAutocomplete"
[displayWith]="displayValueFn"
(optionSelected)="onOptionSelected($event)"
class="tb-autocomplete">
@for (value of filteredValues | async; track value.value) {
<mat-option [value]="value"><span [innerHTML]="value.name | highlight:searchText"></span></mat-option>
<mat-option [value]="value" (mousedown)="$event.preventDefault()"><span [innerHTML]="value.name | highlight:searchText:true"></span></mat-option>
} @empty {
<mat-option [value]="null">{{ 'common.not-found' | translate }}</mat-option>
@if (!allowUserValue) {
<mat-option [value]="null" (mousedown)="$event.preventDefault()">{{ 'common.not-found' | translate }}</mat-option>
}
}
</mat-autocomplete>
<mat-hint [hidden]="!hint">

45
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);

Loading…
Cancel
Save