UI: Add allowUserValue for string items list

This commit is contained in:
Vladyslav_Prykhodko 2025-04-02 13:41:59 +03:00
parent bffa565842
commit 44f1e139bd

View File

@ -14,7 +14,16 @@
/// limitations under the License. /// limitations under the License.
/// ///
import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import {
Component,
DestroyRef,
ElementRef,
forwardRef,
Input,
OnInit,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import { import {
AbstractControl, AbstractControl,
ControlValueAccessor, ControlValueAccessor,
@ -31,6 +40,7 @@ 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 { MatAutocompleteTrigger } from '@angular/material/autocomplete';
import { isDefined } from '@core/utils'; import { isDefined } from '@core/utils';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
export interface StringItemsOption { export interface StringItemsOption {
name: string; name: string;
@ -120,6 +130,10 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
@Input() @Input()
fetchOptionsFn: (searchText?: string) => Observable<Array<StringItemsOption>>; fetchOptionsFn: (searchText?: string) => Observable<Array<StringItemsOption>>;
@Input()
@coerceBoolean()
allowUserValue = false;
get itemsControl(): AbstractControl { get itemsControl(): AbstractControl {
return this.stringItemsForm.get('items'); return this.stringItemsForm.get('items');
} }
@ -132,7 +146,8 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
private propagateChange: (value: any) => void = () => {}; private propagateChange: (value: any) => void = () => {};
private dirty = false; private dirty = false;
constructor(private fb: FormBuilder) { constructor(private fb: FormBuilder,
private destroyRef: DestroyRef) {
this.stringItemsForm = this.fb.group({ this.stringItemsForm = this.fb.group({
item: [null], item: [null],
items: [null] items: [null]
@ -151,6 +166,7 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
} }
}), }),
filter((value) => typeof value === 'string'), filter((value) => typeof value === 'string'),
tap(name => this.searchText = name),
mergeMap(name => this.fetchOptionsFn ? this.fetchOptionsFn(name) : this.fetchValues(name)), mergeMap(name => this.fetchOptionsFn ? this.fetchOptionsFn(name) : this.fetchValues(name)),
share() share()
); );
@ -243,12 +259,20 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
private addItem(value: string) { private addItem(value: string) {
const item = value.trim(); const item = value.trim();
if (item) { if (item) {
if (this.predefinedValues) { if (this.predefinedValues && !this.allowUserValue) {
const findItems = this.predefinedValues const findItems = this.predefinedValues
.filter(value => value.name.toLowerCase().includes(item.toLowerCase())); .filter(value => value.name.toLowerCase().includes(item.toLowerCase()));
if (findItems.length === 1) { if (findItems.length === 1) {
this.add(findItems[0]); this.add(findItems[0]);
} }
} else if (isDefined(this.fetchOptionsFn) && !this.allowUserValue) {
this.fetchOptionsFn(item).pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe((findItems) => {
if (findItems.length === 1) {
this.add(findItems[0]);
}
})
} else { } else {
this.add({value: item, name: item}); this.add({value: item, name: item});
} }
@ -272,7 +296,6 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit {
if (!this.predefinedValues?.length) { if (!this.predefinedValues?.length) {
return of([]); return of([]);
} }
this.searchText = searchText;
let result = this.predefinedValues; let result = this.predefinedValues;
if (searchText && searchText.length) { if (searchText && searchText.length) {
result = this.predefinedValues.filter(option => option.name.toLowerCase().includes(searchText.toLowerCase())); result = this.predefinedValues.filter(option => option.name.toLowerCase().includes(searchText.toLowerCase()));