user9687
user9687

Reputation: 91

What's wrong with my code with Angular and Typescript?

I'm trying to get data from API and bind it to my "headline" property as shown in below code. But what I wrote in the "callback" function: this.headline = res;

does not work, the headline is not bound. However, if I put the same code in the fetchData method, it works! But to me it seems there is no difference? I'm new to Typescript, what am I doing wrong here?

import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
    selector: 'app-home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.css']
})

export class HomeComponent {
    public news: News[];
    public headline: News;
    constructor(private http: HttpClient, @Inject('BASE_URL') private baseUrl: string) {

    }
    ngOnInit() {
        var headurl = this.baseUrl + "api/News/Headline?country=us&category=business";
        this.fetchData(headurl, function (res) {
            //this code does not work
            this.headline = res;
        });

    }

    fetchData(url, callback) {
        this.http.get<News>(url).subscribe(result => {
            callback(result);
            //this code works!
            this.headline = result;
        }, error => console.error(error));

    }
}


interface News {
    SourceId: string;
    SourceName: string;
    Author: string;
    Title: string;
    Description: string;
    Url: string;
    UrlToImage: string;
    PublishedAt: string;
}

Upvotes: 1

Views: 51

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249646

An arrow function captures this from the declaration context while a regular function does not and has this dependent on the caller (basically the caller decides what this to send to the function)

Use the noImplicitThis or strict (although strict turn on a lot more options) compiler options to avoid such errors.

To fix this particular issue also use an arrow function for the first call :

ngOnInit() {
    var headurl = this.baseUrl + "api/News/Headline?country=us&category=business";
    this.fetchData(headurl, (res) => {

        this.headline = res;
    });

}

Upvotes: 1

Igor
Igor

Reputation: 62213

You need to use an arrow function so that this is captured when the callback occurs.

ngOnInit() {
    var headurl = this.baseUrl + "api/News/Headline?country=us&category=business";
    this.fetchData(headurl, (res) => {
        this.headline = res;
    });
}

A better design would be to return an Observable to the caller instead of passing a callback to the the method being called and let the caller decide how to handle the result.

ngOnInit() {
    var headurl = this.baseUrl + "api/News/Headline?country=us&category=business";
    this.fetchData(headurl).subscribe((res) => {
        this.headline = res;
    });
}

fetchData(url) : Observable<News> {
    return this.http.get<News>(url);
}

Upvotes: 1

Related Questions