I currently have this piece of code. I'm using signals, because I understand that's the newest way to achieve what I'm trying to achieve, rather than using an observable, or toPromise(), which is deprecated. And I also understand that using async
/await
syntax is not the way to go about this.
entryArray$ = signal<Entry[]>([]);
getEntryBatch(lemma?: string): Entry[] {
if (lemma) {
this.httpClient
.get<Entry[]>(`${this.url}/entries/l/${lemma}`)
.subscribe((response) => {
this.entryArray$.set(response);
console.log(this.entryArray$()) // this logs the expected response
});
console.log(this.entryArray$()); // this runs too early
} else {
console.log('error catching lemma');
}
console.log(this.entryArray$()); // this runs too early
return this.entryArray$();
}
When I call the function as follows, I don't get the expected response:
this.resultEntries$.set(
this.entriesService.getEntryBatch(this.searchService.mySearch().letter),
);
I've tried changing .subscribe((res) => ...
to .pipe(map((res) =>((res) =>...
because that's what some threads suggest I should be doing in a case like this, but couldn't make it work either. My understanding is that what I need to achieve is for the function getEntryBatch
to return a signal, and then subscribe to the signal when I call the function with getEntryBatch(...).subscribe()
but I can't make any of this work.
Try to use effect
to trigger the data refresh.
effect(() => {
this.entriesService.getEntryBatch(this.searchService.mySearch().letter).subscribe();
});
Then use a getter to access the signal from the service in the component.
get resultEntries$() {
return this.entriesService.entryArray$;
}
Then you can rewrite the service to.
entryArray$ = signal<Entry[]>([]);
getEntryBatch(lemma?: string): Observable<Entry[]> {
return (lemma ? this.httpClient
.get<Entry[]>(`${this.url}/entries/l/${lemma}`) : of([]))
.pipe(tap((response) => {
this.entryArray$.set(response);
});
}
You can use toObservable
to convert the signal to an observable, which will react to changes in the source signal
entryArray$ = toObservable(this.searchService.mySearch()).pipe(
switchMap((mySearch: any) => this.entriesService.getEntryBatch(mySearch.letter)),
);
In the HTML, we can use async pipe ( From JSmith answer )
for( result of entryArray$ | async; track $index ) {
...
}