Browse Source

fix(ui): reactivate tag query

pull/4256/head
KenTandrian 7 months ago
parent
commit
082a1d409c
  1. 4
      libs/ui/src/lib/tags-selector/tags-selector.component.html
  2. 46
      libs/ui/src/lib/tags-selector/tags-selector.component.ts

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

@ -17,7 +17,7 @@
} }
<input <input
#tagInput #tagInput
name="close-outline" [formControl]="tagInputControl"
[matAutocomplete]="autocompleteTags" [matAutocomplete]="autocompleteTags"
[matChipInputFor]="tagsChipList" [matChipInputFor]="tagsChipList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
@ -27,7 +27,7 @@
#autocompleteTags="matAutocomplete" #autocompleteTags="matAutocomplete"
(optionSelected)="onAddTag($event)" (optionSelected)="onAddTag($event)"
> >
@for (tag of tagsUnselected(); track tag.id) { @for (tag of filteredOptions | async; track tag.id) {
<mat-option [value]="tag.id"> <mat-option [value]="tag.id">
{{ tag.name }} {{ tag.name }}
</mat-option> </mat-option>

46
libs/ui/src/lib/tags-selector/tags-selector.component.ts

@ -3,18 +3,18 @@ import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
computed,
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,
effect, effect,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
Input, Input,
OnDestroy,
OnInit, OnInit,
Output, Output,
signal, signal,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { import {
MatAutocompleteModule, MatAutocompleteModule,
MatAutocompleteSelectedEvent MatAutocompleteSelectedEvent
@ -23,6 +23,7 @@ import { MatChipsModule } from '@angular/material/chips';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { Tag } from '@prisma/client'; import { Tag } from '@prisma/client';
import { BehaviorSubject, Subject, takeUntil } from 'rxjs';
@Component({ @Component({
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@ -32,14 +33,15 @@ import { Tag } from '@prisma/client';
MatAutocompleteModule, MatAutocompleteModule,
MatChipsModule, MatChipsModule,
MatFormFieldModule, MatFormFieldModule,
MatInputModule MatInputModule,
ReactiveFormsModule
], ],
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-tags-selector', selector: 'gf-tags-selector',
styleUrls: ['./tags-selector.component.scss'], styleUrls: ['./tags-selector.component.scss'],
templateUrl: 'tags-selector.component.html' templateUrl: 'tags-selector.component.html'
}) })
export class GfTagsSelectorComponent implements OnInit { export class GfTagsSelectorComponent implements OnInit, OnDestroy {
@Input() tags: Tag[]; @Input() tags: Tag[];
@Input() tagsAvailable: Tag[]; @Input() tagsAvailable: Tag[];
@Input() withoutHint: boolean; @Input() withoutHint: boolean;
@ -48,12 +50,12 @@ export class GfTagsSelectorComponent implements OnInit {
@ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>; @ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement>;
public filteredOptions: Subject<Tag[]> = new BehaviorSubject([]);
public readonly tagInputControl = new FormControl('');
public readonly tagsSelected = signal<Tag[]>([]); public readonly tagsSelected = signal<Tag[]>([]);
public readonly separatorKeysCodes: number[] = [COMMA, ENTER]; public readonly separatorKeysCodes: number[] = [COMMA, ENTER];
public readonly tagsUnselected = computed(() => {
const tags = this.tagsSelected(); private unsubscribeSubject = new Subject<void>();
return tags ? this.filterTags(tags) : this.tagsAvailable.slice();
});
public constructor() { public constructor() {
effect(() => { effect(() => {
@ -61,10 +63,21 @@ export class GfTagsSelectorComponent implements OnInit {
this.tagsChanged.emit(this.tagsSelected()); this.tagsChanged.emit(this.tagsSelected());
} }
}); });
this.tagInputControl.valueChanges
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((value) => {
this.filteredOptions.next(this.filterTags(value));
});
} }
public ngOnInit() { public ngOnInit() {
this.tagsSelected.set(this.tags); this.tagsSelected.set(this.tags);
this.updateFilters();
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
} }
public onAddTag(event: MatAutocompleteSelectedEvent) { public onAddTag(event: MatAutocompleteSelectedEvent) {
@ -75,6 +88,7 @@ export class GfTagsSelectorComponent implements OnInit {
return [...(tags ?? []), tag]; return [...(tags ?? []), tag];
}); });
this.tagInput.nativeElement.value = ''; this.tagInput.nativeElement.value = '';
this.tagInputControl.setValue(undefined);
} }
public onRemoveTag(tag: Tag) { public onRemoveTag(tag: Tag) {
@ -83,15 +97,23 @@ export class GfTagsSelectorComponent implements OnInit {
return id !== tag.id; return id !== tag.id;
}); });
}); });
this.updateFilters();
} }
private filterTags(tagsSelected: Tag[]) { private filterTags(query: string = ''): Tag[] {
const tagIds = tagsSelected.map(({ id }) => { const tags = this.tagsSelected() ?? [];
const tagIds = tags.map(({ id }) => {
return id; return id;
}); });
return this.tagsAvailable.filter(({ id }) => { return this.tagsAvailable.filter(({ id, name }) => {
return !tagIds.includes(id); return (
!tagIds.includes(id) && name.toLowerCase().includes(query.toLowerCase())
);
}); });
} }
private updateFilters() {
this.filteredOptions.next(this.filterTags());
}
} }

Loading…
Cancel
Save