diff --git a/libs/ui/src/lib/tags-selector/interfaces/interfaces.ts b/libs/ui/src/lib/tags-selector/interfaces/interfaces.ts new file mode 100644 index 000000000..fe9af9882 --- /dev/null +++ b/libs/ui/src/lib/tags-selector/interfaces/interfaces.ts @@ -0,0 +1,7 @@ +import { Tag } from '@prisma/client'; + +export interface NewTag extends Omit { + id: undefined; +} + +export type SelectedTag = NewTag | Tag; diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.html b/libs/ui/src/lib/tags-selector/tags-selector.component.html index c3c02f3c7..82f465555 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.html +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -2,7 +2,7 @@
@if (readonly) {
Tags
- @if (tags?.length > 0) { + @if (tags && tags.length > 0) { @for (tag of tags; track tag) { {{ tag.name }} diff --git a/libs/ui/src/lib/tags-selector/tags-selector.component.ts b/libs/ui/src/lib/tags-selector/tags-selector.component.ts index 7f1a8805e..36e17f9c1 100644 --- a/libs/ui/src/lib/tags-selector/tags-selector.component.ts +++ b/libs/ui/src/lib/tags-selector/tags-selector.component.ts @@ -7,11 +7,11 @@ import { ElementRef, Input, OnChanges, - OnDestroy, OnInit, signal, - ViewChild + viewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ControlValueAccessor, FormControl, @@ -30,7 +30,9 @@ import { IonIcon } from '@ionic/angular/standalone'; import { Tag } from '@prisma/client'; import { addIcons } from 'ionicons'; import { addCircleOutline, closeOutline } from 'ionicons/icons'; -import { BehaviorSubject, Subject, takeUntil } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; + +import { SelectedTag } from './interfaces/interfaces'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -57,27 +59,28 @@ import { BehaviorSubject, Subject, takeUntil } from 'rxjs'; templateUrl: 'tags-selector.component.html' }) export class GfTagsSelectorComponent - implements ControlValueAccessor, OnChanges, OnDestroy, OnInit + implements ControlValueAccessor, OnChanges, OnInit { @Input() hasPermissionToCreateTag = false; @Input() readonly = false; - @Input() tags: Tag[]; - @Input() tagsAvailable: Tag[]; - - @ViewChild('tagInput') tagInput: ElementRef; + @Input() tags: SelectedTag[]; + @Input() tagsAvailable: SelectedTag[]; - public filteredOptions: Subject = new BehaviorSubject([]); + public readonly filteredOptions: Subject = new BehaviorSubject( + [] + ); public readonly separatorKeysCodes: number[] = [COMMA, ENTER]; public readonly tagInputControl = new FormControl(''); - public readonly tagsSelected = signal([]); + public readonly tagsSelected = signal([]); - private unsubscribeSubject = new Subject(); + private readonly tagInput = + viewChild.required>('tagInput'); public constructor() { this.tagInputControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed()) .subscribe((value) => { - this.filteredOptions.next(this.filterTags(value)); + this.filteredOptions.next(this.filterTags(value ?? '')); }); addIcons({ addCircleOutline, closeOutline }); @@ -106,15 +109,18 @@ export class GfTagsSelectorComponent }; } - this.tagsSelected.update((tags) => { - return [...(tags ?? []), tag]; - }); + if (tag) { + this.tagsSelected.update((tags) => { + return [...(tags ?? []), tag]; + }); - const newTags = this.tagsSelected(); - this.onChange(newTags); - this.onTouched(); - this.tagInput.nativeElement.value = ''; - this.tagInputControl.setValue(undefined); + const newTags = this.tagsSelected(); + this.onChange(newTags); + this.onTouched(); + } + + this.tagInput().nativeElement.value = ''; + this.tagInputControl.setValue(null); } public onRemoveTag(tag: Tag) { @@ -130,7 +136,7 @@ export class GfTagsSelectorComponent this.updateFilters(); } - public registerOnChange(fn: (value: Tag[]) => void) { + public registerOnChange(fn: (value: SelectedTag[]) => void) { this.onChange = fn; } @@ -146,17 +152,12 @@ export class GfTagsSelectorComponent } } - public writeValue(value: Tag[]) { + public writeValue(value: SelectedTag[]) { this.tagsSelected.set(value || []); this.updateFilters(); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - - private filterTags(query: string = ''): Tag[] { + private filterTags(query: string = ''): SelectedTag[] { const tags = this.tagsSelected() ?? []; const tagIds = tags.map(({ id }) => { return id; @@ -170,7 +171,7 @@ export class GfTagsSelectorComponent } // eslint-disable-next-line @typescript-eslint/no-unused-vars - private onChange = (_value: Tag[]): void => { + private onChange = (_value: SelectedTag[]): void => { // ControlValueAccessor onChange callback };