So I am new to signals and I am trying to use them more and more in our application. The part where I still cannot wrap my head around is the connection between rxJS and Signals. Because we are using angulars HTTP client, we have to deal with observables (which is not a bad thing). But now I am trying to make my code more reactive by updating a signals value by doing an API call whenever the ID of the scoped object(which is a signal itself) changes. This is what I came up with:
effect(() => {
this.apiService.hasSomething({
customerId: mySignalWhoseValueChanges()
}).subscribe(value => this.mySignal.set(value));
});
If i use mySignal()
in my template and change mySignalWhoseValueChanges()
, it will call the effect()
because effect()
listens for any signal changes that are used within it.
The thing is, I am 100% sure there is a better approach without using effect()
, but I just do not know. I tried using toSignal()
but this does not work as its not actually a signal thats referenced, but only the value at the time of creating it, or am I missing something:
this.mySignal = toSignal(this.apiService.hasSomething({
customerId: mySignalWhoseValueChanges()
}))
Thanks in advance!
You can combine a signal with an http request pretty easily.
You can use the toObservable
function to watch for changes in/on the signal, then trigger your http request when the id changes.
Note: Signals are NOT meant to be a replacement for RxJS (at least not anytime soon). They are meant to work in unison.
To do this, you would take the following steps:
user
signal to watch for the current user. (this can be anything I chose a number).response
signal to watch for the http response.user
signal.toObservable
and pass your user
signal as the parameter.response
signal with the data.import { toObservable } from '@angular/core/rxjs-interop';
@Component({
selector: 'app-root',
standalone: true,
imports: [HttpClientModule, FormsModule, AsyncPipe, JsonPipe],
styles: ['div{font-family: monospace}'],
template: `
@if ({request: page$ | async}) {
<div>{{response() | json}}</div>
}
<p>Enter a number from 1 to 4.</p>
<input [(ngModel)]="user" />
`,
})
export class App {
user = signal<number>(0); // A way to watch users
response = signal<any>(undefined); // A way to watch for http changes
constructor(private readonly http: HttpClient) {}
page$ = toObservable<number>(this.user).pipe( // Watch for user changes
filter((id) => id > 0), // Only make http request for users larger than 0
tap((id) => console.log('user id', id)), // Just some debugging
exhaustMap((id) => // Don't execute the http request if one is already in progress
this.http
.get<Response>(`https://example.com/user/${id}`) // Make the http request
.pipe(tap((response) => this.response.set(response))) // Update the response
)
);
}