15
votes

I have an Angular 5 application in which I have to call some heavy REST service (usually takes some seconds). I need its result in different part of application, so I would like to store the result in a DataStorageService. Basically, this is I would like to achieve:

@Injectable()
export class DataStorageService {

private result: MyCustomObject;

constructor(private service: Service) {}

getResult(): MyCustomObject {
    if (typeof this.result === 'undefined') {
        // save result
    }
    return result;
}

The question is how I can wait until HTTP request is finished and then save and return the 'result' object. I tried to solve it using Promise and Observable as well, but none of them worked fine.

  1. Observable:

    if (typeof this.result === 'undefined') {
        this.service.call()
            .subscribe(response => this.result = response);
    }
    return this.result;  // wait for save and return MyCustomObject
    
  2. Promise:

    if (typeof this.result === 'undefined') {
        this.service.call()
            .toPromise()
            .then(response => this.result = response);
    }
    return this.result;  // wait for save and return MyCustomObject
    
3
Your getResult(): Promise<MyCustomObject> should also return a promise/observable. Will code the missing codes, when returning from lunch. In the meantime look into github.com/ngrx/store might bring a new solution to the problem. - Thirueswaran Rajagopalan
I would like to avoid returning a Promise or Observable. I need to aggregate the result into different objects according to opened page. This would make my code so ugly if I always have to subscribe to a Promise. Instead of using a simple Object. - aszidien
Note about code clarity and maintenance: Your method is named getResult(), but it actually save the result, so the behavior does not match the name and that leads to confusion - David Votrubec
You're right David. I wrote it from scratch for a better understanding. Maybe it worth to move the save function into an ngOnInit method. - aszidien
I updated my question because the original one was too ambiguous with unnecessary codes. Sorry for that. - aszidien

3 Answers

21
votes

Try using await/async

async getResult(): Promise<MyCustomObject> {
    if (typeof this.result === 'undefined') 
    {
        // save result
        this.result = await this.service.call()
        .toPromise()
        .then(resp =>resp as MyCustomObject);//Do you own cast here

    }
    return this.result;
}
0
votes

I upvoted the response of David above, but I think there may be a design flaw. You should actually not save (in local storage) the result in the getResult function. It's a side effect and it might be undesirable at some point and render your getResult hardly reusable in case you just want to get without save.

Also having the this.result === 'undefined' might create problem as well if you want to refresh the data.

So if you want to get these results in the ngOnInit, you could do it like that:

ngOnInit() {
    if (typeof this.result === 'undefined') {
        this.getResult().then(result => {
            // save the result here
            this.result = result;

            // save in local storage ...
        });
    }
}

getResult(): Promise<MyCustomObject> {
    return this.service.call().toPromise();
}

Note that you cannot await in ngOnInit. But now your getResult() function is reusable in many other cases.

-1
votes

The question is how I can wait until HTTP request is finished and then save and return the 're sult' object.

// Code in service:

ServiceMethod:Observabke<any>(){
     if (typeof this.result === 'undefined') {
                return this.service.call().map(res=>res);
}

// This is code in component.

 componentMethod(){


        return this.service.ServiceMethod()
            .subscribe(response => {
                this.result = response;
               },
               ()=>//handle error,
               () => // call completed { return this.result;  // Subscriber});
    }
    return this.weeklyPlayer;  // MyCustomObject (This return won't wait for http to get completed. Not sure why you want multiple returns.)

    }

Hope this helps.