Browse Source

Merge pull request #15273 from vvlladd28/fix/string-items-list-autocomplete

Fixed string-items-list autocomplete selection and blur handling
pull/15305/head
Vladyslav Prykhodko 6 months ago
committed by GitHub
parent
commit
411b600183
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  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-icon matChipRemove *ngIf="!disabled">close</mat-icon>
</mat-chip-row> </mat-chip-row>
<input matInput type="text" <input matInput type="text"
(blur)="addOnBlur($event)"
placeholder="{{ placeholder }}" placeholder="{{ placeholder }}"
style="max-width: 300px;min-width: 250px" style="max-width: 300px;min-width: 250px"
#stringItemInput #stringItemInput
@ -40,19 +39,23 @@
#origin="matAutocompleteOrigin" #origin="matAutocompleteOrigin"
[matChipInputFor]="itemsChipList" [matChipInputFor]="itemsChipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="true"
matAutocompleteOrigin matAutocompleteOrigin
(matChipInputTokenEnd)="addOnEnd($event)" (matChipInputTokenEnd)="addOnEnd($event)"
[matAutocompleteConnectedTo]="origin" [matAutocompleteConnectedTo]="origin"
[matAutocomplete]="stringItemAutocomplete" [matAutocomplete]="stringItemAutocomplete"
[matAutocompleteDisabled]="!predefinedValues?.length"> [matAutocompleteDisabled]="!predefinedValues?.length && !fetchOptionsFn">
</mat-chip-grid> </mat-chip-grid>
<mat-autocomplete #stringItemAutocomplete="matAutocomplete" <mat-autocomplete #stringItemAutocomplete="matAutocomplete"
[displayWith]="displayValueFn" [displayWith]="displayValueFn"
(optionSelected)="onOptionSelected($event)"
class="tb-autocomplete"> class="tb-autocomplete">
@for (value of filteredValues | async; track value.value) { @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 { } @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-autocomplete>
<mat-hint [hidden]="!hint"> <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 { coerceArray, coerceBoolean } from '@shared/decorators/coercion';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { filter, mergeMap, share, tap } from 'rxjs/operators'; 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'; import { isDefined, isUndefined } from '@core/utils';
export interface StringItemsOption { export interface StringItemsOption {
@ -37,18 +37,18 @@ export interface StringItemsOption {
value: any; value: any;
} }
@Component({ @Component({
selector: 'tb-string-items-list', selector: 'tb-string-items-list',
templateUrl: './string-items-list.component.html', templateUrl: './string-items-list.component.html',
styleUrls: [], styleUrls: [],
providers: [ providers: [
{ {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => StringItemsListComponent), useExisting: forwardRef(() => StringItemsListComponent),
multi: true multi: true
} }
], ],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
standalone: false standalone: false
}) })
export class StringItemsListComponent implements ControlValueAccessor, OnInit { export class StringItemsListComponent implements ControlValueAccessor, OnInit {
@ -149,9 +149,7 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
this.filteredValues = this.itemControl.valueChanges this.filteredValues = this.itemControl.valueChanges
.pipe( .pipe(
tap((value) => { tap((value) => {
if (value && typeof value !== 'string') { if (value === null) {
this.add(value);
} else if (value === null) {
this.clear(); this.clear();
} }
}), }),
@ -209,16 +207,17 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
this.dirty = true; this.dirty = true;
} }
addOnBlur(event: FocusEvent) { onOptionSelected(event: MatAutocompleteSelectedEvent): void {
const target: HTMLElement = event.relatedTarget as HTMLElement; if (event.option.value != null) {
if (target && target.tagName !== 'MAT-OPTION') { this.add(event.option.value);
this.addItem(this.stringItemInput.nativeElement.value ?? '') } else {
this.clear();
} }
this.onTouched();
} }
addOnEnd(event: MatChipInputEvent): void { addOnEnd(event: MatChipInputEvent): void {
this.addItem(event.value ?? '') this.addItem(event.value ?? '');
this.onTouched();
} }
removeItems(item: StringItemsOption) { removeItems(item: StringItemsOption) {
@ -295,6 +294,8 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
this.stringItemInput.nativeElement.value = value; this.stringItemInput.nativeElement.value = value;
this.itemControl.patchValue(value, {emitEvent: true}); this.itemControl.patchValue(value, {emitEvent: true});
setTimeout(() => { setTimeout(() => {
this.stringItemInput.nativeElement.value = value;
this.itemControl.patchValue(null, {emitEvent: false});
this.stringItemInput.nativeElement.blur(); this.stringItemInput.nativeElement.blur();
this.stringItemInput.nativeElement.focus(); this.stringItemInput.nativeElement.focus();
}, 0); }, 0);

Loading…
Cancel
Save