[Angular v16] Signals
Service:
fromObservable & fromSignal
can transform observable to and from signals.
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable, signal } from '@angular/core';
import {
catchError,
filter,
forkJoin,
map,
Observable,
shareReplay,
switchMap,
throwError
} from 'rxjs';
import { fromObservable, fromSignal } from '@angular/core/rxjs-interop';
import { Film, Vehicle, VehicleResponse } from './vehicle';
@Injectable({
providedIn: 'root'
})
export class VehicleService {
private url = 'https://swapi.py4e.com/api/vehicles';
// First page of vehicles
// If the price is empty, randomly assign a price
// (We can't modify the backend in this demo)
private vehicles$ = this.http.get<VehicleResponse>(this.url).pipe(
map((data) =>
data.results.map((v) => ({
...v,
cost_in_credits: isNaN(Number(v.cost_in_credits))
? String(Math.random() * 100000)
: v.cost_in_credits,
}) as Vehicle)
),
shareReplay(1),
catchError(this.handleError)
);
// Expose signals from this service
vehicles = fromObservable<Vehicle[], Vehicle[]>(this.vehicles$, []);
selectedVehicle = signal<Vehicle | undefined>(undefined);
private vehicleFilms$ = fromSignal(this.selectedVehicle).pipe(
filter(Boolean),
switchMap(vehicle =>
forkJoin(vehicle.films.map(link =>
this.http.get<Film>(link)))
)
);
vehicleFilms = fromObservable<Film[], Film[]>(this.vehicleFilms$, []);
constructor(private http: HttpClient) {
}
vehicleSelected(vehicleName: string) {
const foundVehicle = this.vehicles().find((v) => v.name === vehicleName);
this.selectedVehicle.set(foundVehicle);
}
private handleError(err: HttpErrorResponse): Observable<never> {
// in a real world app, we may send the server to some remote logging infrastructure
// instead of just logging it to the console
let errorMessage = '';
if (err.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
errorMessage = `An error occurred: ${err.error.message}`;
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
errorMessage = `Server returned code: ${err.status}, error message is: ${err.message
}`;
}
console.error(errorMessage);
return throwError(() => errorMessage);
}
}
Component:
Only need to refer the signals in service:
import { Component } from '@angular/core';
import { NgFor, NgClass, NgIf, AsyncPipe } from '@angular/common';
import { VehicleService } from '../vehicle.service';
@Component({
selector: 'sw-vehicle-list',
standalone: true,
imports: [AsyncPipe, NgClass, NgFor, NgIf],
templateUrl: './vehicle-list.component.html'
})
export class VehicleListComponent {
pageTitle = 'Vehicles';
errorMessage = '';
// Component signals
vehicles = this.vehicleService.vehicles;
selectedVehicle = this.vehicleService.selectedVehicle;
constructor(private vehicleService: VehicleService) { }
// When a vehicle is selected, emit the selected vehicle name
onSelected(vehicleName: string): void {
this.vehicleService.vehicleSelected(vehicleName);
}
}
Template:
<div class="card">
<div class="card-header">
{{pageTitle}}
</div>
<div class='card-body'
*ngIf="vehicles().length">
<div class="list-group">
<button type="button"
class="list-group-item"
*ngFor="let vehicle of vehicles()"
[ngClass]="{'active': vehicle?.name === selectedVehicle()?.name}"
(click)="onSelected(vehicle.name)">
{{ vehicle.name }}
</button>
</div>
</div>
<div class="alert alert-danger"
*ngIf="errorMessage">
{{errorMessage }}
</div>
</div>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2019-04-13 [Docker] Converting from Docker Compose to Kubernetes
2018-04-13 [HTML5] Accessible Icon Buttons
2017-04-13 [Angular] Create custom validators for formControl and formGroup
2016-04-13 [Docker] Docker Machine intro
2016-04-13 [Javascript] JavaScript Array Methods in Depth - push
2015-04-13 [AngularJS + Webpack] require directives
2015-04-13 [AngularJS + Webpack] Using Webpack for angularjs