Kavita/UI/Web/src/app/shared/edit-list/edit-list.component.ts
2025-05-06 19:51:28 +02:00

93 lines
2.5 KiB
TypeScript

import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
EventEmitter,
inject,
Input,
OnInit,
Output
} from '@angular/core';
import {AsyncValidatorFn, FormArray, FormControl, FormGroup, ReactiveFormsModule, ValidatorFn} from "@angular/forms";
import {TranslocoDirective} from "@jsverse/transloco";
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {debounceTime, distinctUntilChanged, tap} from "rxjs/operators";
@Component({
selector: 'app-edit-list',
imports: [ReactiveFormsModule, TranslocoDirective],
templateUrl: './edit-list.component.html',
styleUrl: './edit-list.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class EditListComponent implements OnInit {
private readonly cdRef = inject(ChangeDetectorRef);
private readonly destroyRef = inject(DestroyRef);
@Input({required: true}) items: Array<string> = [];
@Input({required: true}) label = '';
@Input() validators: ValidatorFn[] = []
@Input() asyncValidators: AsyncValidatorFn[] = [];
// TODO: Make this more dynamic based on which validator failed
@Input() errorMessage: string | null = null;
@Output() updateItems = new EventEmitter<Array<string>>();
form: FormGroup = new FormGroup({items: new FormArray([])});
get ItemsArray(): FormArray {
return this.form.get('items') as FormArray;
}
ngOnInit() {
this.items.forEach(item => this.addItem(item));
this.form.valueChanges.pipe(
debounceTime(100),
distinctUntilChanged(),
tap(data => this.emit()),
takeUntilDestroyed(this.destroyRef))
.subscribe();
this.cdRef.markForCheck();
}
createItemControl(value: string = ''): FormControl {
return new FormControl(value, this.validators, this.asyncValidators);
}
add() {
this.ItemsArray.push(this.createItemControl());
this.emit();
this.cdRef.markForCheck();
}
addItem(value: string) {
this.ItemsArray.push(this.createItemControl(value));
}
remove(index: number) {
// If it's the last item, just clear its value
if (this.ItemsArray.length === 1) {
this.ItemsArray.at(0).setValue('');
this.emit();
this.cdRef.markForCheck();
return;
}
this.ItemsArray.removeAt(index);
this.emit();
this.cdRef.markForCheck();
}
// Emit non-empty item values
emit() {
const nonEmptyItems = this.ItemsArray.controls
.map(control => control.value)
.filter(value => value !== null && value.trim() !== '');
this.updateItems.emit(nonEmptyItems);
}
}