Browse Source

Task/improve type safety in symbol autocomplete (#6498)

* Improve type safety in symbol autocomplete
pull/6499/head
Kenrick Tandrian 1 week ago
committed by GitHub
parent
commit
4dabd8ae68
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      libs/common/src/lib/interfaces/lookup-item.interface.ts
  2. 61
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts

2
libs/common/src/lib/interfaces/lookup-item.interface.ts

@ -7,7 +7,7 @@ export interface LookupItem {
assetSubClass: AssetSubClass; assetSubClass: AssetSubClass;
currency: string; currency: string;
dataProviderInfo: DataProviderInfo; dataProviderInfo: DataProviderInfo;
dataSource: DataSource; dataSource: DataSource | null;
name: string; name: string;
symbol: string; symbol: string;
} }

61
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.ts

@ -8,15 +8,17 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
DestroyRef,
DoCheck, DoCheck,
ElementRef, ElementRef,
Input, Input,
OnChanges, OnChanges,
OnDestroy,
OnInit, OnInit,
SimpleChanges, SimpleChanges,
ViewChild inject,
viewChild
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { import {
FormControl, FormControl,
FormsModule, FormsModule,
@ -35,13 +37,12 @@ import {
import { MatInput, MatInputModule } from '@angular/material/input'; import { MatInput, MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { isString } from 'lodash'; import { isString } from 'lodash';
import { Subject, tap } from 'rxjs'; import { tap } from 'rxjs';
import { import {
debounceTime, debounceTime,
distinctUntilChanged, distinctUntilChanged,
filter, filter,
switchMap, switchMap
takeUntil
} from 'rxjs/operators'; } from 'rxjs/operators';
import { translate } from '../i18n'; import { translate } from '../i18n';
@ -77,21 +78,21 @@ import { AbstractMatFormField } from '../shared/abstract-mat-form-field';
}) })
export class GfSymbolAutocompleteComponent export class GfSymbolAutocompleteComponent
extends AbstractMatFormField<LookupItem> extends AbstractMatFormField<LookupItem>
implements DoCheck, OnChanges, OnDestroy, OnInit implements DoCheck, OnChanges, OnInit
{ {
@Input() public defaultLookupItems: LookupItem[] = []; @Input() public defaultLookupItems: LookupItem[] = [];
@Input() public isLoading = false; @Input() public isLoading = false;
@ViewChild('symbolAutocomplete') public symbolAutocomplete: MatAutocomplete;
@Input() private includeIndices = false; @Input() private includeIndices = false;
@ViewChild(MatInput) private input: MatInput; public readonly control = new FormControl();
public control = new FormControl();
public lookupItems: (LookupItem & { assetSubClassString: string })[] = []; public lookupItems: (LookupItem & { assetSubClassString: string })[] = [];
private unsubscribeSubject = new Subject<void>(); protected readonly symbolAutocomplete =
viewChild.required<MatAutocomplete>('symbolAutocomplete');
private readonly destroyRef = inject(DestroyRef);
private readonly input = viewChild.required(MatInput);
public constructor( public constructor(
public readonly _elementRef: ElementRef, public readonly _elementRef: ElementRef,
@ -105,13 +106,22 @@ export class GfSymbolAutocompleteComponent
this.controlType = 'symbol-autocomplete'; this.controlType = 'symbol-autocomplete';
} }
public get empty() {
return this.input().empty;
}
public set value(value: LookupItem) {
this.control.setValue(value);
super.value = value;
}
public ngOnInit() { public ngOnInit() {
if (this.disabled) { if (this.disabled) {
this.control.disable(); this.control.disable();
} }
this.control.valueChanges this.control.valueChanges
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => { .subscribe(() => {
if (super.value) { if (super.value) {
super.value.dataSource = null; super.value.dataSource = null;
@ -136,7 +146,7 @@ export class GfSymbolAutocompleteComponent
}), }),
debounceTime(400), debounceTime(400),
distinctUntilChanged(), distinctUntilChanged(),
takeUntil(this.unsubscribeSubject), takeUntilDestroyed(this.destroyRef),
switchMap((query: string) => { switchMap((query: string) => {
return this.dataService.fetchSymbols({ return this.dataService.fetchSymbols({
query, query,
@ -168,12 +178,8 @@ export class GfSymbolAutocompleteComponent
return aLookupItem?.symbol ?? ''; return aLookupItem?.symbol ?? '';
} }
public get empty() {
return this.input?.empty;
}
public focus() { public focus() {
this.input.focus(); this.input().focus();
} }
public isValueInOptions(value: string) { public isValueInOptions(value: string) {
@ -185,7 +191,7 @@ export class GfSymbolAutocompleteComponent
public ngDoCheck() { public ngDoCheck() {
if (this.ngControl) { if (this.ngControl) {
this.validateRequired(); this.validateRequired();
this.errorState = this.ngControl.invalid && this.ngControl.touched; this.errorState = !!(this.ngControl.invalid && this.ngControl.touched);
this.stateChanges.next(); this.stateChanges.next();
} }
} }
@ -197,18 +203,6 @@ export class GfSymbolAutocompleteComponent
} as LookupItem; } as LookupItem;
} }
public set value(value: LookupItem) {
this.control.setValue(value);
super.value = value;
}
public ngOnDestroy() {
super.ngOnDestroy();
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
}
private showDefaultOptions() { private showDefaultOptions() {
this.lookupItems = this.defaultLookupItems.map((lookupItem) => { this.lookupItems = this.defaultLookupItems.map((lookupItem) => {
return { return {
@ -224,8 +218,9 @@ export class GfSymbolAutocompleteComponent
const requiredCheck = super.required const requiredCheck = super.required
? !super.value?.dataSource || !super.value?.symbol ? !super.value?.dataSource || !super.value?.symbol
: false; : false;
if (requiredCheck) { if (requiredCheck) {
this.ngControl.control.setErrors({ invalidData: true }); this.ngControl.control?.setErrors({ invalidData: true });
} }
} }
} }

Loading…
Cancel
Save