httpResource is convenient. It is Signal-based and re-runs the request whenever Signals used inside the request change. Personally, I like Resource.reload(). Most Angular users probably routed HTTP through services with code like this:
@Injectable({...})
export class ExampleService {
readonly #http = inject(HttpClient);
// When handling the request with a Promise
getDataPromise(id: string): Promise<Data> {
return firstValueFrom(this.#http.get<Data>(environment.api + 'example/' + id));
}
// Observable-based
getDataObservable(id: string): Observable<Data> {
return this.#http.get<Data>(environment.api + 'example/' + id);
}
}
Whether I reflected that in the template with the async pipe or assigned it to a component property, it was familiar code for a long time. Now I can write it like this:
@Injectable({...})
export class ExampleService {
readonly #http = inject(HttpClient);
// When handling the request with a Promise
getData(id: Signal<string>): HttpResourceRef<Data> {
return httpResource<Data>(environment.api + 'example/' + id());
}
}
I bind it directly on the component:
@Component({...})
export class ExamplePage {
readonly id = input.required<number>();
readonly #exampleService = inject(ExampleService);
readonly dataResource = this.#exampleService.getData(this.id);
}
The main thing to watch is passing the Signal itself as an argument, not unwrapping its value. Requests are handled by Signal values without lifecycle hooks—simple and very nice. I recommend trying it.
With Ionic Angular, the code looks like this (for the ViewDidEnter property, see https://zenn.dev/rdlabo/articles/bb03d724d33831):
@Component({...})
export class ExamplePage {
readonly id = input.required<number>();
readonly el = inject(ElementRef);
readonly #didEnter = toSignal(createDidEnter(this.el));
readonly #exampleService = inject(ExampleService);
readonly dataResource = this.#exampleService.getData(this.#didEnter, this.id);
}
@Injectable({...})
export class ExampleService {
readonly #http = inject(HttpClient);
getData(didEnter: Signal<boolean>, id: Signal<string>): HttpResourceRef<Data> {
return httpResource<IMovie[]>(() => {
if (!didEnter()) {
return undefined;
}
return environment.api + 'example/' + id();
});
}
}
Compared to before, I can write this much more simply. The API is still experimental, but give it a try!