// user.service.ts import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, map, catchError, of } from 'rxjs'; interface User { id: number; name: string; } @Injectable({ providedIn: 'root' }) export class UserService { private http = inject(HttpClient); // Returns just an array of name strings, or [] if the request fails. getUserNames(): Observable { return this.http.get('https://jsonplaceholder.typicode.com/users').pipe( map((users) => users.map((u) => u.name)), catchError((err) => { console.error('Failed to load users:', err); return of([]); }) ); } } // user-names.component.ts import { Component, inject } from '@angular/core'; import { AsyncPipe } from '@angular/common'; import { UserService } from './user.service'; @Component({ selector: 'app-user-names', standalone: true, imports: [AsyncPipe], template: ` @if (names$ | async; as names) { } `, }) export class UserNamesComponent { private userService = inject(UserService); names$ = this.userService.getUserNames(); } /* Notes: - map transforms the stream's value — here turning User[] into a plain string[] of names before it ever reaches the component. - catchError intercepts a failed request and returns of([]) — an Observable that emits a single empty array — so the UI shows an empty list instead of erroring out. - This pipeline is RxJS's equivalent of transforming data and wrapping it in try/catch, all composed in one place. */