Browse Source

Task/improve type safety in tags selector component (#6497)

* Improve type safety
pull/6089/merge
Kenrick Tandrian 1 week ago
committed by GitHub
parent
commit
7c20bfff92
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      libs/ui/src/lib/tags-selector/interfaces/interfaces.ts
  2. 2
      libs/ui/src/lib/tags-selector/tags-selector.component.html
  3. 49
      libs/ui/src/lib/tags-selector/tags-selector.component.ts

7
libs/ui/src/lib/tags-selector/interfaces/interfaces.ts

@ -0,0 +1,7 @@
import { Tag } from '@prisma/client';
export interface NewTag extends Omit<Tag, 'id'> {
id: undefined;
}
export type SelectedTag = NewTag | Tag;

2
libs/ui/src/lib/tags-selector/tags-selector.component.html

@ -2,7 +2,7 @@
<div class="col">
@if (readonly) {
<div class="h5" i18n>Tags</div>
@if (tags?.length > 0) {
@if (tags && tags.length > 0) {
<mat-chip-listbox>
@for (tag of tags; track tag) {
<mat-chip-option disabled>{{ tag.name }}</mat-chip-option>

49
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<HTMLInputElement>;
@Input() tags: SelectedTag[];
@Input() tagsAvailable: SelectedTag[];
public filteredOptions: Subject<Tag[]> = new BehaviorSubject([]);
public readonly filteredOptions: Subject<SelectedTag[]> = new BehaviorSubject(
[]
);
public readonly separatorKeysCodes: number[] = [COMMA, ENTER];
public readonly tagInputControl = new FormControl('');
public readonly tagsSelected = signal<Tag[]>([]);
public readonly tagsSelected = signal<SelectedTag[]>([]);
private unsubscribeSubject = new Subject<void>();
private readonly tagInput =
viewChild.required<ElementRef<HTMLInputElement>>('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,6 +109,7 @@ export class GfTagsSelectorComponent
};
}
if (tag) {
this.tagsSelected.update((tags) => {
return [...(tags ?? []), tag];
});
@ -113,8 +117,10 @@ export class GfTagsSelectorComponent
const newTags = this.tagsSelected();
this.onChange(newTags);
this.onTouched();
this.tagInput.nativeElement.value = '';
this.tagInputControl.setValue(undefined);
}
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
};

Loading…
Cancel
Save