Angular 2 - 导航到用户详细信息页面不显示选定的用户详细信息

Angular 2 - Navigating to user details page doesn't show selected user details

我正在尝试创建一个用户详细信息页面,您可以在其中获取有关所选用户的更多信息。 当您单击列表中的用户名时,它会成功导航到用户详细信息页面,但会抛出此错误:

Unhandled Promise rejection: Error in src/person-details.component.html:3:25 caused by: Cannot read property 'id' of undefined

这是一个插曲: http://embed.plnkr.co/cUEIag77etv95ZFJY3iN/

代码如下:

人-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { IPerson } from './person';
import { AppService } from './app.service';

@Component({
  selector: 'my-list',
  templateUrl: 'src/person-list.component.html'
})

export class PersonListComponent implements OnInit {

  _persons: IPerson[];
  selectedPerson: IPerson;

  constructor(
    private _appService: AppService,
    private router: Router) { }

  ngOnInit(): void {
    this._appService.getPersons()
      .subscribe(
      _persons => this._persons = _persons); // set our local _persons array equal to the IPerson[] data which arrive from our data stream
  }

  goToDetails(person: IPerson): void {
    this.router.navigate(['/user', person.id])
  }
}

人-list.component.html

<div class="container-fluid">
  <div class='table-responsive'>
    <table class='table'>
      <thead>
        <tr>
          <th>Id</th>
          <th>Name</th>
        </tr>
      </thead>

      <tbody>
        <tr *ngFor="let person of _persons" (click)="goToDetails(person)" class="row">
          <td>{{person.id}}</td>
          <td>{{person.name}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

人-details.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';

import { AppService } from './app.service';
import { IPerson } from './person';

@Component({
  selector: 'my-details',
  templateUrl: 'src/person-details.component.html'
})

export class PersonDetailsComponent implements OnInit {

  constructor(
    private _appService: AppService,
    private route: ActivatedRoute,
    private location: Location
  ) { }

  ngOnInit(): void {
    this.route.params.forEach((params: Params) => { // delivers our array of route parameters.
      let id = +params['id']; // The person id is a number. Route parameters are always strings. So we convert the route parameter value to a number with the JavaScript (+) operator.
      this._appService.getPerson(id)
        .map(person => this.person = person);
    });
  }

  // navigates backward one step in the browser's history stack using the Location service we injected 
  goBack(): void {
    this.location.back();
  }
}

人-details.component.html

<div class="container">
  <h3>Person Details</h3>
  <div class="col-md-12">
    <div><span>Id:</span> {{person.id}}</div>
    <div><span>Name:</span> {{person.name}}</div>
    <div><span>Description:</span> {{person.description}}</div>
  </div>
  <button (click)="goBack()">Back</button>
</div>

app.service.ts

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http'; // required for getting persons from JSON file
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map'; // required by the .map method

import { IPerson } from './person';

@Injectable() export class AppService {

    private _personUrl = 'src/persons.json';

    constructor(private _http: Http) { } // required to Inject Http as a dependency. Creates a private _http variable and assigns the injected service instance to that variable

    getPersons(): Observable<IPerson[]> {
        return this._http.get(this._personUrl)
            .map((response: Response) => <IPerson[]>response.json().personData); // we let the compiler know that the array contains items of type 'IPerson' and return the 'personData' object from the json file as an array
    }

    // filters the person list from getPersons by id
    getPerson(id: number): Observable<IPerson> {
        return this.getPersons()
            .map(persons => persons.find(person => person.id === id));
    }
}

初始化 PersonDetailsComponent 时,字段 person 为空,这会导致模板绑定出错。您可以使用 field?.subfield.

替换模板绑定来说明这一点
<div class="container">
  <h3>Person Details</h3>
  <div class="col-md-12">
    <div><span>Id:</span> {{person?.id}}</div>
    <div><span>Name:</span> {{person?.name}}</div>
    <div><span>Description:</span> {{person?.description}}</div>
  </div>
  <button (click)="goBack()">Back</button>
</div>

我将您的 plunker 编辑为具有这些更改的版本。我还需要编辑 PersonDetailsComponent 以订阅 getPerson() observable。