Reputation: 21
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!
Upvotes: 0
Views: 1910
Reputation: 115
You can use model input here, link to docs: https://angular.dev/guide/signals/model.
Like so: items = model<CheckBoxItem[]>([]);
But if you want the same approach as you have, you can probably use transform property on input, and have signal input and output.
disableTooltipChange = output<string>()
disabledTooltip = input<string>('', {
transform: (v: string | boolean) => {
this.disableTooltipChange.emit(v)
return v ;
}
});
Something along these line, you can check docs here for how to transform the signals line with using setter: https://v17.angular.io/api/core/InputSignalWithTransform
Upvotes: 1
Reputation: 17758
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)"
/>
Upvotes: 2