Search code examples
angularangular2-servicesangular2-http

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"}]

Solution

  • 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(.....).