Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Have component execute function after service http.get call is finished

I'm having real trouble wrapping my head around observables and subscriptions in angular2. The problem I am currently having is the following:

I have a service which contains methods to post and get data from an API. The service is injected into a component, which directly calls those methods in the service. The service then retrieves data and stores it itself, but I then want to process that data within the component. I cannot work out how to have the component execute a function after the service has retrieved and stored the data itself.

service.ts

import { Injectable } from 'angular2/core';    
import { Http } from 'angular2/router';

@Injectable()
export class Service {
    result: Object;

    constructor(http: Http) {
        this.http = http;
    }

    httpGet(url) {
        return this.http.get(url).subscribe(
            result => this.result = result.json(),
            error => console.log(error),
            () => {}
        )
    }
}

component.ts

import { Component } from 'angular2/core';
import { Service } from './service';

@Component({
    ...
})
export class Component {
    formattedResult: Object;

    constructor(service: Service) {
        this.service = service;
        this.service.httpGet('/api')

        // How do I call format result on service.result only after it is completed?
        this.formatResult(service.result) // Need to execute this after the http call is completed

        // I want something like:
        this.service.httpGet('/api').then(() => formatResult(this.service.result));
    }

    formatResult(result) {
        this.formattedResult = result.map(x => x.length) // For example
    }
}
like image 409
Peter Trotman Avatar asked Jan 12 '16 14:01

Peter Trotman


2 Answers

To answer my own question:

In the app root, import Rxjs with:

import 'rxjs/Rx';

This gives you access to the complete Observable object (not just the 'Observable-lite' included with Angular). This enables you to .map .reduce etc. the Http requests.

You can now use .map on an Http request to carry out arbitrary code in the context of the service, even if it is the component that subscribes to the result. So to achieve what I set out to do in the beginning, we can:

service.ts

import { Injectable } from 'angular2/core';    
import { Http } from 'angular2/router';

@Injectable()
export class Service {
    result: Object;

    constructor(http: Http) {
        this.http = http;
    }

    httpGet(url) {
        return this.http.get(url).map(
            result => {
                let data = result.json();
                this.result = data;
                return data
            }
        )
    }
}

component.ts

import { Component } from 'angular2/core';
import { Service } from './service';

@Component({
    // Component setup
})
export class Component {
    formattedResult: Object;

    constructor(service: Service) {
        this.service = service;
        this.service.httpGet('/api').subscribe(
            data => this.formatResult(data);
        );
    }

    formatResult(result) {
        this.formattedResult = result.map(x => x.length) // For example
    }
}

Thanks to Gunter and Mark for the replies, helped me wrap my head around this a bit and I feel like I understand Observables much better having gone through a lot of the docs solving this problem!

like image 82
Peter Trotman Avatar answered Nov 07 '22 12:11

Peter Trotman


Check if the result already arrived, if yes, create a new promise and complete it with the result, not not, fetch it, and return it as promise as well.

@Injectable()
export class Service {
    result: Object;

    constructor(http: Http) {
        this.http = http;
    }

    httpGet(url) {
        if(result === undefined) {
          return this.http.get(url).toPromise().then(
              result => this.result = result.json(),
              error => console.log(error);
          );
        } else {
          return new Promise().resolve(result);
        }
    }
}

I don't know TS and this code might contain some errors (I use Angular only Dart), but you should get the idea.

See also
- http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

like image 2
Günter Zöchbauer Avatar answered Nov 07 '22 12:11

Günter Zöchbauer