I have a searchbar component that emits on change of the input field so that the consumer can do filtering of list results or call the API with the searchterm as param.
However I also want to provide the possibilty to set a searchterm from the consumers. I already implemented this once with Observables. In our new project we try to learn lots about signals and implement as much as possible with signals.
So I've been refactoring the component and came up with a working solution. But I couldn't find a way to ditch the @Input() setter
.
Maybe some of you know how to do this the "signal-way".
Here's what I got:
inpage-search.component.ts
import { ChangeDetectionStrategy, Component, Input, input, OnInit, output, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ClarityModule } from '@clr/angular';
import { TranslateModule } from '@ngx-translate/core';
import { debounceTime, distinctUntilChanged, Subject } from 'rxjs';
@Component({
selector: 'shared-inpage-search',
standalone: true,
imports: [FormsModule, TranslateModule, ClarityModule],
templateUrl: './inpage-search.component.html',
styleUrl: './inpage-search.component.css',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InpageSearchComponent implements OnInit {
readonly placeholder = input<string>();
readonly label = input<string>();
@Input() set searchTerm(searchTerm: string) {
this.searchTermSignal.set(searchTerm);
this.searchTermChange.emit(searchTerm);
}
readonly searchTermSignal = signal<string>('');
readonly searchTermChange = output<string>();
private readonly debounceSearchTermSubject = new Subject<string>();
ngOnInit(): void {
this.debounceSearchTermSubject
.pipe(distinctUntilChanged(), debounceTime(200))
.subscribe((searchTerm: string) => this.searchTermChange.emit(searchTerm));
}
debounceSearchTerm(searchTerm: string) {
this.debounceSearchTermSubject.next(searchTerm);
}
}
inpage-search.component.html
<clr-input-container>
<label>{{ label() }}</label>
<input
clrInput
class="search-term-input"
[placeholder]="placeholder()"
[ngModel]="searchTermSignal()"
(ngModelChange)="debounceSearchTerm($event)"
/>
</clr-input-container>
My Goal would be to replace
@Input() set searchTerm(searchTerm: string) {
this.searchTermSignal.set(searchTerm);
this.searchTermChange.emit(searchTerm);
}
readonly searchTermSignal = signal<string>('');
with an input signal while still be able to trigger the emit whenever the input value changes.
All the help is much appreciated, Cheers!
You can use a model input:
export class MyDirective {
searchTerm = model('');
}
And use it like the following:
<input
clrInput
class="search-term-input"
[placeholder]="placeholder()"
[searchTerm]="searchTermSignal()"
(searchTermChange)="debounceSearchTerm($event)"
/>