简体   繁体   中英

Angular 2 http get observable

I am new to Angular 2, coming from a Jquery background. I am struggling with the simple things.

My first task is to populate a HTML Table from an API that is serving me JSON.

The problem is before I even try and create the html I am trying to populate an array of mail class objects from json, but it keeps coming back undefined. I have checked in fiddler and the json is being served.

I have created:

  • get-mail.service.ts to download the json
  • inbboxmail.component.html|ts|css to be the view
  • mail.ts to be my model

get-mail.service.ts - Here the .map function console log is coming back with the entire json (as I expected) but the .do console log is undefined

import { Injectable, Inject } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs';
import { Mail } from "../model/mail"   // My Model

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class GetMailService {

    constructor(private http: Http, @Inject('ORIGIN_URL') private originUrl: string) {}

  getMail(): Observable<Mail[]> {
      return this.http.get(this.originUrl + '/api/mail/')
          // ...and calling .json() on the response to return data
          .map((res: Response) => { res.json(); console.log("map", res.json()); })  //This is coming back with my entire json
          .do(data => console.log("all:" + JSON.stringify(data))) //all: undefined
          //...errors if any
          .catch((error:any) => Observable.throw(error.json().error || 'Server error'));
  }

}

inboxmail.component.ts //all console logs are coming back undefined

import { Component, Inject } from '@angular/core';
import { GetMailService } from '../../../services/get-mail.service';
import { Observable } from 'rxjs';
import { Mail } from '../../../model/mail'

@Component({
    selector: 'inboxmail',
    templateUrl: './inboxmail.component.html',
    styleUrls: ['./inboxmail.component.css'],
    providers: [GetMailService]

})
export class InboxMailComponent {
    public mail: Mail[];

    constructor(private service: GetMailService) {
        service.getMail()
            .subscribe(_mail => { console.log("mail", _mail); this.mail = _mail },  
                 null,
                 () => console.log("complete", this.mail));
    }

}

Mail Model

export class Mail {
    constructor(
        public reference: string,
        public ocrText: string,
        public status: string,
        public create: Date
    ) { }
}

served json (shortened for example purposes)

[{"reference":"1897","ocrText":"magna adipiscing euismod euismod elit . ","status":"Stored","created":"2017-07-04T14:09:25.2565869Z"},{"reference":"1897","ocrText":"magna adipiscing euismod euismod elit . ","status":"Stored","created":"2017-07-04T14:09:25.2565869Z"}]

Change the service method to:

getMail(): Observable<Mail[]> {
    /*return this.http.request('./data/people.json')
        .map(res => res.json());*/
      return this.http.get(this.originUrl + '/api/mail/')
          // ...and calling .json() on the response to return data
          .map((res: Response) => { console.log("map", res.json());return res.json(); })  //This is coming back with my entire json
          .do(data => console.log("all:" + JSON.stringify(data))) //all: undefined
          //...errors if any
          .catch((error:any) => Observable.throw(error.json().error || 'Server error'));
  }

And change the definition of your data model to an interface as follows:

export interface Mail {
    reference: string;
    ocrText: string;
    status: string;
    create: Date;
}

Why an interface? Well, your service is returning an string in JSON format that can be mapped to POJOs whos properties can be defined by an interface. If you want to use a class, you need to map every single POJO to an instance of that class by using new Mail(.....).

I suggest to converted the Observable to a Promise using the toPromise operator, since Promise may be easier to understand than Observable .

import 'rxjs/add/operator/toPromise';
getHero(id: number): Promise<Hero> {
  const url = `${this.heroesUrl}/${id}`;
  return this.http.get(url)
    .toPromise()
    .then(response => response.json().data as Hero)
    .catch(this.handleError);
}

See the official tutorial here .

Here is your problem:

.map((res: Response) => { res.json(); console.log("map", res.json()); })

When you call res.json() , it returns the JSON object but you don't actually forward it to the next step in your stream (the do() ). Change that line to

.map((res: Response) => res.json())

Now you are returning the JSON object, which will be available as input to your do() and will be emitted in your Subscription

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