Angular:在ngFor中传递单个对象至路由链接组件
Hey, let's break down how you can pass the diary object to your page-view component when clicking those links. Since you're dealing with route-based navigation (not direct parent-child communication), there are a couple of solid approaches here—let's start with the service method you're curious about, then cover other options too.
First, a quick note: Your diary property in VolumeLinksComponent is typed as String, but it should be an array (since you're using *ngFor on it). I'll fix that in the code examples below.
Method 1: Shared Service (Best for complex objects/avoiding URL exposure)
This is the approach you mentioned wanting to learn. We'll create a service to hold the selected diary object, set it when the link is clicked, and subscribe to it in the page-view component.
Step 1: Create the shared service
// diary-shared.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class DiarySharedService { // BehaviorSubject holds the current value and emits it to new subscribers private selectedDiarySubject = new BehaviorSubject<any | null>(null); selectedDiary$ = this.selectedDiarySubject.asObservable(); setSelectedDiary(diary: any) { this.selectedDiarySubject.next(diary); } }
Step 2: Update the VolumeLinks component
First, add a click handler to your <a> tag to pass the diary object to the service:
<!-- volume-links.component.html --> <ul class="navigation"> <li *ngFor="let d of diary"> <a id="{{d.notebook_id}}" routerLink="/page-view" routerLinkActive="active" (click)="onDiaryClick(d)" >Volume {{d.notebook_id}}, {{ d.date }}, {{ d.volume_id }}, Add MS {{ d.ms_id }}</a> </li> </ul>
Then update the component class to inject the service and handle the click:
// volume-links.component.ts import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { DiarySharedService } from './diary-shared.service'; // Import the service @Component({ selector: 'app-volume-links', templateUrl: './volume-links.component.html', styleUrls: ['./volume-links.component.scss'], }) export class VolumeLinksComponent implements OnInit { diary: any[] = []; // Fix the type to array constructor( private http: HttpClient, private diarySharedService: DiarySharedService // Inject the service ) { } ngOnInit() { this.http.get('/api/diaries').subscribe(data => { this.diary = data["data"]["docs"]; console.log(this.diary); }) } onDiaryClick(diary: any) { // Set the selected diary in the service this.diarySharedService.setSelectedDiary(diary); } }
Step 3: Get the selected diary in PageView component
Subscribe to the service's observable to receive the diary object:
// page-view.component.ts import { Component, OnInit, OnDestroy } from '@angular/core'; import { DiarySharedService } from './diary-shared.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-page-view', templateUrl: './page-view.component.html', styleUrls: ['./page-view.component.scss'], }) export class PageViewComponent implements OnInit, OnDestroy { selectedDiary: any; private subscription: Subscription | undefined; constructor(private diarySharedService: DiarySharedService) { } ngOnInit() { // Subscribe to the selected diary updates this.subscription = this.diarySharedService.selectedDiary$.subscribe(diary => { if (diary) { this.selectedDiary = diary; // Add your logic here (e.g., load related data) } }); } ngOnDestroy() { // Clean up the subscription to prevent memory leaks if (this.subscription) { this.subscription.unsubscribe(); } } }
Method 2: Route State (Angular 7+, no service needed)
If you don't want to use a service, you can pass the object directly in the route state (it won't show up in the URL, but will be lost if the user refreshes the page).
Update VolumeLinks template
<!-- volume-links.component.html --> <ul class="navigation"> <li *ngFor="let d of diary"> <a id="{{d.notebook_id}}" [routerLink]="['/page-view']" [state]="{ selectedDiary: d }" routerLinkActive="active" >Volume {{d.notebook_id}}, {{ d.date }}, {{ d.volume_id }}, Add MS {{ d.ms_id }}</a> </li> </ul>
Get state in PageView component
// page-view.component.ts import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-page-view', templateUrl: './page-view.component.html', styleUrls: ['./page-view.component.scss'], }) export class PageViewComponent implements OnInit { selectedDiary: any; constructor(private route: ActivatedRoute) { } ngOnInit() { // Retrieve the state from the route snapshot const navigation = this.route.snapshot.navigation; if (navigation?.extras.state) { this.selectedDiary = navigation.extras.state['selectedDiary']; } } }
Method 3: Query Params (URL-visible, simple objects)
If you don't mind the diary data appearing in the URL, you can serialize the object to a JSON string and pass it as a query parameter.
Update VolumeLinks template
<!-- volume-links.component.html --> <ul class="navigation"> <li *ngFor="let d of diary"> <a id="{{d.notebook_id}}" [routerLink]="['/page-view']" [queryParams]="{ diary: JSON.stringify(d) }" routerLinkActive="active" >Volume {{d.notebook_id}}, {{ d.date }}, {{ d.volume_id }}, Add MS {{ d.ms_id }}</a> </li> </ul>
Parse params in PageView component
// page-view.component.ts import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-page-view', templateUrl: './page-view.component.html', styleUrls: ['./page-view.component.scss'], }) export class PageViewComponent implements OnInit { selectedDiary: any; constructor(private route: ActivatedRoute) { } ngOnInit() { this.route.queryParams.subscribe(params => { if (params['diary']) { this.selectedDiary = JSON.parse(params['diary']); } }); } }
内容的提问来源于stack exchange,提问作者Alcamech

