0

Today i'm facing a new problem with services.

I'm trying to make an http service but when I try to store, in my service, the Observable object returned by http.get.map - my app crashs.

I wanted to achieve a "system" where the service loops to update datas and the components which subscribed to the observable update its data according to the service's data.

Here is the code :

afficheur.component.ts :

import { Component } from '@angular/core';
import {HardwareService} from "../../services/hardware.service";

@Component({
    selector: 'afficheur',
    templateUrl: 'app/components/hardware/afficheur.component.html'
})
export class AfficheurComponent{
    public state: Boolean;
    constructor(private service: HardwareService){
        this.service
            .getHardware()
            .subscribe(data => (console.log(data), this.state = data.afficheur),
                error => console.log(error),
                () => console.log('Get etat afficheur complete'))
    }
}

hardware.service.ts :

import { Injectable, OnInit }              from '@angular/core';
import { Headers, Http, Response }          from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';

@Injectable()
export class HardwareService implements OnInit{
    private apiUrl = 'http://10.72.23.11:5000';  // URL to web API

    private ressources: Observable<any>;

    constructor (private http: Http) {}

    ngOnInit() {
        this.loopupdate()
    }

    loopupdate(): void {
        setInterval(() => {
            this.update();
        }, 5000);
    }

    update(): void {
        this.ressources = this.http.get(this.apiUrl)
            .map(this.extractData)
            .catch(this.handleError);
    }

    getHardware(){
        return this.ressources;
    }

    private extractData(res: Response) {
        let body = res.json();
        return body || { };
    }
    private handleError (error: Response | any) {
        // In a real world app, you might use a remote logging infrastructure
        let errMsg: string;
        if (error instanceof Response) {
            const body = error.json() || '';
            const err = body.error || JSON.stringify(body);
            errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
        } else {
            errMsg = error.message ? error.message : error.toString();
        }
        console.error(errMsg);
        return Observable.throw(errMsg);
    }
}

app.module.ts :

    import { FormsModule } from '@angular/forms';
    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { HttpModule }    from '@angular/http';

    import { AppComponent } from './app.component';


    import { ROUTING } from './app.routes';
    import {HardwareService} from "./services/hardware.service";
    import {AfficheurComponent} from "./components/hardware/afficheur.component";
    import {HardwareListComponent} from "./views/hardwarelist/hardwarelist.component";


    @NgModule({
        imports: [ BrowserModule, ROUTING, HttpModule, FormsModule, HttpModule],
        declarations: [
            AppComponent,
            AfficheurComponent,
            HardwareListComponent
        ],
        bootstrap: [ AppComponent ],
        providers: [ HardwareService ]
    })

export class AppModule { }

Thanks again for being here :D

EDIT :

I got an error when i try to launch my app :

ERROR TypeError: Cannot read property 'subscribe' of undefined

I think it's related to the this.ressources initialization, any idea ?


EDIT 2 : In my service :

initializePolling(){
        return IntervalObservable.create(5000)
            .flatMap(() => {
                return this.getHardware()
        });
    }

getHardware(): Observable<any> {
        return this.http.get(this.apiUrl)
            .map(this.extractData)
            .catch(this.handleError);
    }

How can i subscribe to this with my component ? I don't know what method i should call in my component to fetch datas without make multiple calls if i have multiple components.

Jérémy JOKE
  • 271
  • 4
  • 15

1 Answers1

2

The problem is that ngOnInit(), like the one in your Injectable class, is a Lifecycle hook which only works with Directives and Components. You should try calling this.loopUpdate() from within the Injectable class' constructor. You can know more about this on another thread/question.

If you want to set an interval in fetching the data, do that in the component class, not in the service. In the service you should just have methods that return Observables (in your case) from calling http.get().... In that way you wouldn't have an undefined object returned and a more reusable service.

Also, here's another SO link for you to have look at.

Rax Weber
  • 3,730
  • 19
  • 30
  • I'll update right now my post with an error i get. I used ngOnInit() cause i wanted the Observable initiated and i think it's the problem here cause "ERROR TypeError: Cannot read property 'subscribe' of undefined", any idea ? – Jérémy JOKE May 23 '17 at 16:27
  • @JérémyJOKE Updated my answer. – Rax Weber May 23 '17 at 16:34
  • The problem is that all my compenents use the same service (provider) so if i create 2 afficheur.component, it multiplicates by 2 the number of calls on the api. That's why i wanted the service to loops and the compenents update themselves according to service's data. – Jérémy JOKE May 23 '17 at 16:40
  • @JérémyJOKE Added another SO link to my answer. – Rax Weber May 23 '17 at 16:56
  • How my component can subscribe to an Observable (IntervalObservable) ? I don't know how to figure it out. Post updated in 2 secs – Jérémy JOKE May 24 '17 at 09:13
  • I'll vote for your answer, it made the initial thread solved. I'll open a new one to get some help on Observable and IntervalObservable. Thank you again. – Jérémy JOKE May 24 '17 at 11:51