HappyCoder
HappyCoder

Reputation: 6155

Returning data from a service to a component in Angular

I am busy writing a service to return data to a component in my angular app (ng4). The data is retrieved from a smart contract.

I seem to be getting the following error:

HomeComponent_Host.html:1 ERROR TypeError: this.smartContractService.getDrawId(...).subscribe is not a function

My component code:

    this.smartContractService.getDrawId().subscribe(data => {
        console.log('Result:: ', data);
    });

And my service method:

getDrawId(): Observable<any> {
    let gameObject;
    return this.Game
        .deployed()
        .then(instance => {
            gameObject = instance;
            return gameObject.getDrawId.call();
        })
        .then(value => {
            return value; //console.log(value) returns the data.
        })
        .catch(error => {
            console.error('Error getting draw id; see log.');
            console.log(error);
        });
}

I am not sure how to get the data back from the service and to the calling component...

Upvotes: 0

Views: 407

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84902

You seem to be trying to combine promises and observables. Promises and observables have a bit of similarity, since they're both intended to deal with asynchronous things. But while promises only ever deal with 1 eventual value, Observables deal with a stream of 0, 1, or many values.

Apparently, this.Game.deployed() is returning a promise, because you're calling .then on it (which is the way you interact with promises). However, getDrawId claims to return an Observable<any>, and you're calling .subscribe; a function that only exists on observables, not promises.

So the path forward depends on what your intent is. Since this.game.deployed returns a promise, perhaps you want to use promises throughout, in which case you can do this:

getDrawId(): Promise<any> { //<--- type changed
    let gameObject;
    return this.Game
        .deployed()
        .then(instance => {
            gameObject = instance;
            return gameObject.getDrawId.call();
        })
        .then(value => {
            return value; //console.log(value) returns the data.
        })
        .catch(error => {
            console.error('Error getting draw id; see log.');
            console.log(error);
        });
}

// And use it with .then instead of .subscribe
this.smartContractService.getDrawId().then(data => {
    console.log('Result:: ', data);
});

Alternatively, maybe you want getDrawId to return an observable, in which case you could either do a larger refactor in which you make this.Game.deployed() use observables so that you're using them throughout; or you could leave that as is and create an observable around the promise:

getDrawId(): Observable<any> {
    let gameObject;
    return Observable.fromPromise(this.Game
        .deployed()
        .then(instance => {
            gameObject = instance;
            return gameObject.getDrawId.call();
        })
        .then(value => {
            return value; //console.log(value) returns the data.
        })
        .catch(error => {
            console.error('Error getting draw id; see log.');
            console.log(error);
        });
    );
}

Also, while I left in the <any>s from your code, i'd recommend making a more specific type if you know it.

Upvotes: 2

Related Questions