mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
4.1 KiB
168 lines
4.1 KiB
import { FocusMonitor } from '@angular/cdk/a11y';
|
|
import {
|
|
CUSTOM_ELEMENTS_SCHEMA,
|
|
ChangeDetectionStrategy,
|
|
ChangeDetectorRef,
|
|
Component,
|
|
DestroyRef,
|
|
DoCheck,
|
|
ElementRef,
|
|
OnInit,
|
|
ViewChild,
|
|
inject,
|
|
input,
|
|
viewChild
|
|
} from '@angular/core';
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
import {
|
|
FormControl,
|
|
FormGroupDirective,
|
|
FormsModule,
|
|
NgControl,
|
|
ReactiveFormsModule
|
|
} from '@angular/forms';
|
|
import {
|
|
MatAutocomplete,
|
|
MatAutocompleteModule,
|
|
MatOption
|
|
} from '@angular/material/autocomplete';
|
|
import {
|
|
MatFormFieldControl,
|
|
MatFormFieldModule
|
|
} from '@angular/material/form-field';
|
|
import { MatInput, MatInputModule } from '@angular/material/input';
|
|
import { map, startWith } from 'rxjs/operators';
|
|
|
|
import { AbstractMatFormField } from '../shared/abstract-mat-form-field';
|
|
|
|
@Component({
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
host: {
|
|
'[attr.aria-describedBy]': 'describedBy',
|
|
'[id]': 'id'
|
|
},
|
|
imports: [
|
|
FormsModule,
|
|
MatAutocompleteModule,
|
|
MatFormFieldModule,
|
|
MatInputModule,
|
|
ReactiveFormsModule
|
|
],
|
|
providers: [
|
|
{
|
|
provide: MatFormFieldControl,
|
|
useExisting: GfCurrencySelectorComponent
|
|
}
|
|
],
|
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
selector: 'gf-currency-selector',
|
|
styleUrls: ['./currency-selector.component.scss'],
|
|
templateUrl: 'currency-selector.component.html'
|
|
})
|
|
export class GfCurrencySelectorComponent
|
|
extends AbstractMatFormField<string | null>
|
|
implements DoCheck, OnInit
|
|
{
|
|
@ViewChild('currencyAutocomplete')
|
|
public currencyAutocomplete: MatAutocomplete;
|
|
|
|
public readonly control = new FormControl<string | null>(null);
|
|
public readonly currencies = input.required<string[]>();
|
|
public filteredCurrencies: string[] = [];
|
|
public readonly formControlName = input.required<string>();
|
|
|
|
private readonly destroyRef = inject(DestroyRef);
|
|
private readonly input = viewChild.required(MatInput);
|
|
|
|
public constructor(
|
|
public readonly _elementRef: ElementRef,
|
|
public readonly _focusMonitor: FocusMonitor,
|
|
public readonly changeDetectorRef: ChangeDetectorRef,
|
|
private readonly formGroupDirective: FormGroupDirective,
|
|
public readonly ngControl: NgControl
|
|
) {
|
|
super(_elementRef, _focusMonitor, ngControl);
|
|
|
|
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() {
|
|
if (this.disabled) {
|
|
this.control.disable();
|
|
}
|
|
|
|
const formGroup = this.formGroupDirective.form;
|
|
|
|
if (formGroup) {
|
|
const control = formGroup.get(this.formControlName());
|
|
|
|
if (control) {
|
|
this.value =
|
|
this.currencies().find((value) => {
|
|
return value === control.value;
|
|
}) ?? null;
|
|
}
|
|
}
|
|
|
|
this.control.valueChanges
|
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
.subscribe(() => {
|
|
if (super.value) {
|
|
super.value = null;
|
|
}
|
|
});
|
|
|
|
this.control.valueChanges
|
|
.pipe(
|
|
takeUntilDestroyed(this.destroyRef),
|
|
startWith(''),
|
|
map((value) => {
|
|
return value ? this.filter(value) : this.currencies().slice();
|
|
})
|
|
)
|
|
.subscribe((values) => {
|
|
this.filteredCurrencies = values;
|
|
});
|
|
}
|
|
|
|
public ngDoCheck() {
|
|
if (this.ngControl) {
|
|
this.validateRequired();
|
|
this.errorState = !!(this.ngControl.invalid && this.ngControl.touched);
|
|
this.stateChanges.next();
|
|
}
|
|
}
|
|
|
|
public onUpdateCurrency({ option }: { option: MatOption<string> }) {
|
|
super.value = option.value;
|
|
}
|
|
|
|
private filter(value: string) {
|
|
const filterValue = value.toLowerCase();
|
|
|
|
return this.currencies().filter((currency) => {
|
|
return currency.toLowerCase().startsWith(filterValue);
|
|
});
|
|
}
|
|
|
|
private validateRequired() {
|
|
const requiredCheck = super.required ? !super.value : false;
|
|
|
|
if (requiredCheck) {
|
|
this.ngControl.control?.setErrors({ invalidData: true });
|
|
}
|
|
}
|
|
}
|
|
|