antilles
antilles

Reputation: 7

Angular2 http.get data will not render in html template

I'm new to Angular2 and I'm struggling with getting the data returned from an http.get() Observable to display in my html. I have narrowed down the problem to get() calls to one of my api's. If I use another api endpoint, the data displays without issue in the html. I know my api is retrieving the data because when I console.log() the data, the expected output is there.

Service

//color.service.ts
import { Injectable } from '@angular/core'
import { Observable } from 'rxjs/RX'
import { Http, Response, Headers, RequestOptions } from '@angular/http'

@Injectable()
export class ColorService {

   constructor(private http:Http){
   }

   getColors():Observable<IColor[]> {
      return this.http.get('/colors')
      .map((response: Response) => {
         return <IColor[]>response.json();
      })
   }
}

Component

//color.component.ts
import { Component, OnInit } from '@angular/core';
import { ColorService } from './shared/color.service';
import { IColor } from './shared/outage.model';

@Component({
    template: `
        <h4>Colors[]</h4>
        <div *ngFor="let c of colors">{{ c.colorDesc }}</div>
    `
})
export class ColorComponent implements OnInit {
    colors: IColor[];

    constructor(private colorService:ColorService ) {}

    ngOnInit(){
        this.colorService.getColors().subscribe(data => {
            console.log(data);
            this.colors = data;
        })
    }
}

IColor is a simple interface:

export interface IColor {
   colorDesc: string;
}

The resulting html output is simply the <h4>Colors[]</h4> heading; however, you can see in the console log that the call to http.get('/colors') was successful and the IColor[] object is populated. An inspection of the DOM shows that there are empty <div> elements, created by the *ngFor.

As mentioned above, an http.get() to another endpoint works as expected: the data is shown in the html. I am struggling to understand why data from another api will not show in the DOM. It does appear to take 1-2 seconds longer to retrieve, but my understanding of Observable subscriptions is that these are async operations; when it completes, the html should render the data from the *ngFor.

Upvotes: 0

Views: 1135

Answers (1)

bryan60
bryan60

Reputation: 29315

If the divs are rendering but no data is populated, then there is a mismatch between what you parse out of your response and what you are binding to the template. I'd hunt for typos, but anecdotally, I have a lot of issues using interfaces and the angular CLI. I usually need to re compile everytime I edit an interface.

I'd try getting rid of that explicit typing in your map function, it isn't needed, it's already inferred from the return type of the function and doesn't actually do anything helpful. I can't comment further without seeing your data returned.

Secondly, a better way to bind observables to templates is with the async pipe rather than subscribing in your component.ts, like so:

colors$ : Observable<IColor[]>;

constructor(private colorService:ColorService ) {}

ngOnInit(){
    this.colors$ = this.colorService.getColors().do(e => console.log(e)); //do just for debugging
}

and template:

<div *ngFor="let c of colors$ | async">{{ c.colorDesc }}</div>

The reasons for this are it is cleaner, more declarative, and most importantly the async pipe handles garbage collection for you.

Upvotes: 1

Related Questions