Browse Source

Task/improve type safety in currency selector (#6402)

* feat(lib): resolve typescript errors

* feat(lib): make input a view child signal

* feat(lib): remove unsubscribe subject

* feat(lib): remove ngOnDestroy

* feat(lib): make currencies an input signal

* feat(lib): make formControlName an input signal
pull/6264/head
Kenrick Tandrian 3 days ago
committed by GitHub
parent
commit
69740db292
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 90
      libs/ui/src/lib/currency-selector/currency-selector.component.ts

90
libs/ui/src/lib/currency-selector/currency-selector.component.ts

@ -4,13 +4,16 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
DestroyRef,
DoCheck, DoCheck,
ElementRef, ElementRef,
Input,
OnDestroy,
OnInit, OnInit,
ViewChild ViewChild,
inject,
input,
viewChild
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { import {
FormControl, FormControl,
FormGroupDirective, FormGroupDirective,
@ -21,15 +24,14 @@ import {
import { import {
MatAutocomplete, MatAutocomplete,
MatAutocompleteModule, MatAutocompleteModule,
MatAutocompleteSelectedEvent MatOption
} from '@angular/material/autocomplete'; } from '@angular/material/autocomplete';
import { import {
MatFormFieldControl, MatFormFieldControl,
MatFormFieldModule MatFormFieldModule
} from '@angular/material/form-field'; } from '@angular/material/form-field';
import { MatInput, MatInputModule } from '@angular/material/input'; import { MatInput, MatInputModule } from '@angular/material/input';
import { Subject } from 'rxjs'; import { map, startWith } from 'rxjs/operators';
import { map, startWith, takeUntil } from 'rxjs/operators';
import { AbstractMatFormField } from '../shared/abstract-mat-form-field'; import { AbstractMatFormField } from '../shared/abstract-mat-form-field';
@ -58,21 +60,19 @@ import { AbstractMatFormField } from '../shared/abstract-mat-form-field';
templateUrl: 'currency-selector.component.html' templateUrl: 'currency-selector.component.html'
}) })
export class GfCurrencySelectorComponent export class GfCurrencySelectorComponent
extends AbstractMatFormField<string> extends AbstractMatFormField<string | null>
implements DoCheck, OnDestroy, OnInit implements DoCheck, OnInit
{ {
@Input() private currencies: string[] = [];
@Input() private formControlName: string;
@ViewChild(MatInput) private input: MatInput;
@ViewChild('currencyAutocomplete') @ViewChild('currencyAutocomplete')
public currencyAutocomplete: MatAutocomplete; public currencyAutocomplete: MatAutocomplete;
public control = new FormControl(); public readonly control = new FormControl<string | null>(null);
public readonly currencies = input.required<string[]>();
public filteredCurrencies: string[] = []; public filteredCurrencies: string[] = [];
public readonly formControlName = input.required<string>();
private unsubscribeSubject = new Subject<void>(); private readonly destroyRef = inject(DestroyRef);
private readonly input = viewChild.required(MatInput);
public constructor( public constructor(
public readonly _elementRef: ElementRef, public readonly _elementRef: ElementRef,
@ -86,6 +86,19 @@ export class GfCurrencySelectorComponent
this.controlType = 'currency-selector'; this.controlType = 'currency-selector';
} }
public get empty() {
return this.input().empty;
}
public set value(value: string | null) {
this.control.setValue(value);
super.value = value;
}
public focus() {
this.input().focus();
}
public ngOnInit() { public ngOnInit() {
if (this.disabled) { if (this.disabled) {
this.control.disable(); this.control.disable();
@ -94,17 +107,18 @@ export class GfCurrencySelectorComponent
const formGroup = this.formGroupDirective.form; const formGroup = this.formGroupDirective.form;
if (formGroup) { if (formGroup) {
const control = formGroup.get(this.formControlName); const control = formGroup.get(this.formControlName());
if (control) { if (control) {
this.value = this.currencies.find((value) => { this.value =
return value === control.value; this.currencies().find((value) => {
}); return value === control.value;
}) ?? null;
} }
} }
this.control.valueChanges this.control.valueChanges
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => { .subscribe(() => {
if (super.value) { if (super.value) {
super.value = null; super.value = null;
@ -113,10 +127,10 @@ export class GfCurrencySelectorComponent
this.control.valueChanges this.control.valueChanges
.pipe( .pipe(
takeUntil(this.unsubscribeSubject), takeUntilDestroyed(this.destroyRef),
startWith(''), startWith(''),
map((value) => { map((value) => {
return value ? this.filter(value) : this.currencies.slice(); return value ? this.filter(value) : this.currencies().slice();
}) })
) )
.subscribe((values) => { .subscribe((values) => {
@ -124,42 +138,22 @@ export class GfCurrencySelectorComponent
}); });
} }
public get empty() {
return this.input?.empty;
}
public focus() {
this.input.focus();
}
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();
} }
} }
public onUpdateCurrency(event: MatAutocompleteSelectedEvent) { public onUpdateCurrency({ option }: { option: MatOption<string> }) {
super.value = event.option.value; super.value = option.value;
}
public set value(value: string) {
this.control.setValue(value);
super.value = value;
}
public ngOnDestroy() {
super.ngOnDestroy();
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
} }
private filter(value: string) { private filter(value: string) {
const filterValue = value?.toLowerCase(); const filterValue = value.toLowerCase();
return this.currencies.filter((currency) => { return this.currencies().filter((currency) => {
return currency.toLowerCase().startsWith(filterValue); return currency.toLowerCase().startsWith(filterValue);
}); });
} }
@ -168,7 +162,7 @@ export class GfCurrencySelectorComponent
const requiredCheck = super.required ? !super.value : false; const requiredCheck = super.required ? !super.value : false;
if (requiredCheck) { if (requiredCheck) {
this.ngControl.control.setErrors({ invalidData: true }); this.ngControl.control?.setErrors({ invalidData: true });
} }
} }
} }

Loading…
Cancel
Save