简体   繁体   中英

Angular2 Service Returns Undefined

For some reason my services aren't working. I've been lurking SO for two days trying to find similar questions, but they don't fit my problem.

Service.ts:

import { Injectable } from '@angular/core';
import {  Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { CarObject } from './make';

@Injectable()
export class EdmundsService {
  private stylesurl = 'REDACTED';

 constructor(private http: Http) { }

 getCars(): Observable<CarObject[]> {
   return this.http.get(this.stylesurl)
   .map(this.extractData)
   .catch(this.handleError);
  }

  private extractData(res: Response) {
   let body = res.json();
   return body.data || { };
  }
  private handleError (error: Response | any) {
  // In a real world app, we might use a remote logging infrastructure
   let errMsg: string;
   if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
     } else {
      errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
  }

}

These are my 'models':

class Style {
  id: number;
  name: string;
  make: Make;
  model: Model;
  year: Year;
  submodel: Submodel;
  trim: string;
  states: string[];
  engine: Engine;
  transmission: Transmission;
  options: Options[];
  colors: Color[];
  drivenWheels: string;
  numOfDoors: string;
  squishVins: string[];
  categories: Categories;
  MPG: MPG;
  manufacturerOptionCode: string;
 }

export class CarObject {
styles: Style[];
stylesCount: number;
}

My component:

import { CarObject } from './make';
import { EdmundsService } from './edmunds-search-result.service';

@Component({REDACTED
providers: [EdmundsService] })


export class EdmundsSearchResultComponent implements OnInit {
  cars: CarObject[];
  errorMessage: string;



  constructor(private _edmundsService: EdmundsService) { }

   getCars(): void {
     this._edmundsService.getCars()
     .subscribe(
      cars => this.cars = cars,
      error =>  this.errorMessage = <any>error);
   }


  ngOnInit(): void {
   this.getCars();
  }

}

Component HTML: {{ cars.stylesCount | async }}

Sample API Response: http://pastebin.com/0LyZuPGW

Error Output:

EXCEPTION: Error in ./EdmundsSearchResultComponent class 
EdmundsSearchResultComponent - inline template:0:0 caused by: 
Cannot read    property 'stylesCount' of undefined
  1. CarObject was designed to match the API Response, so it could be okay to remove the array brackets ( [] )
  2. I don't know why this won't display the object data on my template despite closely following the Tour Of Heroes HTTP/Services tutorial.

What I am trying to do is make an HTTP request from variable 'styleurl' (which I see is successfully made by checking the 'Network' tab in chrome dev tools.) Using this API Response, I want my CarObject to 'consume' the json response, and be available to my component/template.

In your component you're reserving your car property, but you don't initialize it, so it remains undefined .

At the time your HTML renders the promise isn't fulfilled yet, your car is still undefined but you try to access a property from it.

A couple solutions:

preset it :

cars: CarObject = new CarObject(); // or <CarObject>{}

use the elvis operator in your template :

 {{ cars?.stylesCount }}

use ngIf :

 <div *ngIf="cars">{{ cars.styleCount }}</div>

There are probably a couple of more ways to handle this case.

See my update at the bottom regarding your usage of the async pipe. It probably leads to errors as well in the way you're trying to use it.


Besides, i would suggest reading up on TypeScript types as well as general best practices for angular and typescript especially regarding the usage of models, interfaces and such. Also using Observables would be a good idea instead of Promises. There are some issues in your code, so this is just a hint, but elaborating on them has no place here i think and aren't the source of your problem.

Hope i could help.


Update:

About your usage of the async pipe:

The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted.

You use it on an array of CarObjects which btw shouldn't be an array. Take a look at the documentation for the async pipe for proper usage.

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