简体   繁体   中英

Angular 2 - Cannot read property '…' of undefined

Very new to Angular. I checked similar questions but they either dive into specifics or I just don't understand the solutions.

The actual error: "Cannot read property 'idPlanet' of undefined at Object.eval [as updateRenderer] (PlanetComponent.html:11)"

The issue: planetDetail.idPlanet is undefined most probably?

Suspect: getPlanetDetail()

planet.component.html:

<div class="col-sm-9">
  ID: {{ planetDetail.idPlanet }}
</div>

planet.component.ts:

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

import { Planet }               from './planet';
import { PlanetService }        from './planet.service';

@Component({
  selector: 'planets',
  templateUrl: './planet.component.html'
})
export class PlanetComponent implements OnInit {

    private planets: Planet[];
    private planetDetail: Planet;
    constructor(
        private planetService: PlanetService
    ) {}

    public ngOnInit(): void {
      this.getPlanetDetail();
      this.getPlanets();
    }

    public getPlanets() {
      this.planetService.getPlanets()
          .subscribe(
              (planets) => this.planets = planets
          );
    }

    public getPlanetDetail() {
      this.planetService.getPlanetDetail()
          .subscribe(
              (planets) => this.planetDetail = planets
          );
    }

}

planet.service.ts:

import { Injectable }    from '@angular/core';
import { Headers, Http, Response } from '@angular/http';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import { Planet } from './planet';

@Injectable()
export class PlanetService {

    private planetsUrl = 'http://localhost/index.php/api/planet/';  // URL to web api

    // Injecting the http client into the service
    constructor(private http: Http) {}

    public getPlanets(): Observable<Planet[]> {
        return this.http.get(this.planetsUrl + 'planets/id_sol/1')
            .map(this.parseData)
            .catch(this.handleError);
    }

    public getPlanetDetail(): Observable<Planet> {
      return this.http.get(this.planetsUrl + 'planet/id_planet/1')
          .map(this.parseData)
          .catch(this.handleError);
    }

    private parseData(res: Response) {
        let body = res.json();

        if (body instanceof Array) {
            return body || [];
        } else {
            return body.post || {};
        }
    }

    private handleError(error: any): Promise<any> {
        console.error('An error occurred', error); // for demo purposes only
        return Promise.reject(error.message || error);
    }
}

I'm at a loss tbh, I tried to build my getPlanetDetail() method from getPlanets() which works fine. Should I use a promise?

I'm having a hard time figuring out where exactly I can put console.log() to debug. I'm using angular-starter kit from Github.

Thanks for your time.

edit 1: the api outputs {"idPlanet":"1","name":"Earth"}

As the request is asynchronous sometime the value will not be fetched from the server when the page loads, therefore, the planetDetail is undefined. in order to avoid this you can use add '?' between planetDetail and idPlanet. that prints only if it has the value

ID: {{ planetDetail?.idPlanet }}

If you want to print the result or error public getPlanetDetail() { this.planetService.getPlanetDetail() .subscribe( (planets) => { console.log(planets); this.planetDetail = planets }, error => {console.log(error);} ); } public getPlanetDetail() { this.planetService.getPlanetDetail() .subscribe( (planets) => { console.log(planets); this.planetDetail = planets }, error => {console.log(error);} ); }

my friend to debug if your 'planetDetail' is populated, just add 'console.log (planetDetail)' in the 'subscribe' method. Follow the example below.

public getPlanetDetail() {
  this.planetService.getPlanetDetail()
      .subscribe(
          (planets) => this.planetDetail = planets
      );
}

public getPlanetDetail() {
  this.planetService.getPlanetDetail()
      .subscribe(
          (planets) => this.planetDetail = planets, (err) => (err), () => console.log(this.palnetDetail)
      );
}

More about subscribe()

 subscribe(function(response) { console.log("Success Response" + response) }, function(error) { console.log("Error happened" + error) }, function() { console.log("the subscription is completed") }); 

Since your response is {"idPlanet":"1","name":"Earth"} , try the following:

public getPlanetDetail(): Observable<Planet> {
    return this.http.get(this.planetsUrl + 'planet/id_planet/1')
        .map(res => res.json())
        .catch(this.handleError);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM