Angular’s evolving ecosystem is shifting toward a more functional and reactive programming paradigm. With tools like Signals, the Resource API, and the inject function, developers can simplify application logic, reduce boilerplate, and enhance reusability.
This blog post explores how Angular’s modern features empower developers to handle asynchronous logic in a clean, declarative, and reactive way.
For this example, we’ll fetch posts from a REST API. Each post has the following structure:
export interface Post { userId: number; id: number; title: "string;" body: string; }
The base URL for the API is provided via an InjectionToken:
import { InjectionToken } from '@angular/core'; export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL', { providedIn: 'root', factory: () => 'https://jsonplaceholder.typicode.com', });
The following function fetches a post by its ID using Angular’s HttpClient:
import { HttpClient } from '@angular/common/http'; import { inject } from '@angular/core'; import { Observable } from 'rxjs'; import { API_BASE_URL } from '../tokens/base-url.token'; import { Post } from './post.model'; export function getPostById(postId: number): Observable<Post> { const http = inject(HttpClient); const baseUrl = inject(API_BASE_URL); return http.get<Post>(`${baseUrl}/posts/${postId}`); }
To use this function in a component, you can bind it to an observable and display the result with the async pipe:
import { AsyncPipe, JsonPipe } from '@angular/common'; import { Component, signal } from '@angular/core'; import { getPostById } from './shared/posts.inject'; @Component({ selector: 'app-root', standalone: true, imports: [AsyncPipe, JsonPipe], template: ` @if (post$ | async; as post) { <p>{{ post | json }}</p> } @else { <p>Loading...</p> } `, }) export class AppComponent { private readonly postId = signal(1); protected readonly post$ = getPostById(this.postId()); }
The Resource API simplifies reactivity and state management. Here’s a function that uses the Resource API:
import { inject, resource, ResourceRef, Signal } from '@angular/core'; import { API_BASE_URL } from '../tokens/base-url.token'; export function getPostByIdResource(postId: Signal<number>): ResourceRef<Post> { const baseUrl = inject(API_BASE_URL); return resource<Post, { id: number }>({ request: () => ({ id: postId() }), loader: async ({ request, abortSignal }) => { const response = await fetch(`${baseUrl}/posts/${request.id}`, { signal: abortSignal, }); return response.json(); }, }); }
This approach:
In a component:
export interface Post { userId: number; id: number; title: "string;" body: string; }
The Resource API automatically manages states like loading, error, and success. This removes the need for custom flags and ensures cleaner templates.
The Resource API is tightly integrated with Signals. Changes to a Signal automatically trigger the loader function, ensuring that your UI always reflects the latest data.
Errors are centralized and exposed via .error(), simplifying error management in templates.
The API cancels ongoing requests when dependencies (e.g., postId) change, preventing race conditions and stale data.
Feature | RxJS (Observable) | Resource API (Signal) |
---|---|---|
State Management | Manual | Automatic (loading, error) |
Reactivity | Requires custom setup | Built-in |
Error Handling | Manual | Declarative |
Lifecycle Handling | Requires cleanup | Automatic |
Angular’s inject function and Signal-based Resource API represent a leap forward in simplifying asynchronous logic. With these tools, developers can:
The Resource API, in particular, is ideal for modern Angular projects, providing automatic reactivity and declarative state handling. Start exploring these features today and take your Angular development to the next level!
The above is the detailed content of Functional Programming in Angular: Exploring inject and Resources. For more information, please follow other related articles on the PHP Chinese website!