16

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
    
5
  • 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. Commented Mar 23, 2018 at 8:00
  • 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. Commented Mar 23, 2018 at 8:08
  • 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 Commented Mar 23, 2018 at 8:21
  • 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. Commented Mar 23, 2018 at 8:57
  • I updated my question because the original one was too ambiguous with unnecessary codes. Sorry for that. Commented Mar 23, 2018 at 9:31

3 Answers 3

21

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;
}
Sign up to request clarification or add additional context in comments.

2 Comments

should not the method signature be: async getResult(): Promise<MyCustomObject> ?
Why are this answer accepted as correct? this is not synchronous, this is just using async/await instead promises. Sync request must be supported by the http library and must mark The underlay xmlHtppRequest as synchrnous. The question is probably wrong though. developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/….
0

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 Comment

This was actually mentioned in the comments of the OP by David Votrubec.
-1

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.

5 Comments

Not my downvote, but I guess it's because your code does not wait for the http call to finish to assign and return the value
If you are talking about "return this.weekPlayer" I have added in comment that it wont work. And for this result, It is assigned in subsrcibe and returned when call is completed.
I didn't downvote it. Anyway, I already tried something very similar. If I call this method from a component, it also returns with a Subscriber instead of MyCustomObject. As far as I understand, I must use Promise with await/async to wait for service response. It's not possible to solve my problem with Observable.
Oh wait. If you want to call it from component, its other way. I am updating my answer.
Thank you Dheeraj, I really appreciate your help. Maybe I'm wrong, but I don't think it's solvable with Observable in any way. If I call "getResult()" in a component it always returns with a Subscriber instead of my real object. The only solution which worked if I mapped Observable to Promise and used await/async keywords to pause the execution and wait for the resolution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.