简体   繁体   中英

Wait for a Subscription and a Promise in Angular 4

I'm new to Angular 4, so I accept that I may be better off changing my approach.

What I have is this:

ngOnInit() {
    this.route.paramMap
        .switchMap((params: ParamMap) => {
            var id = +params.get('id');
            return this.service.getOne(id);
        }).subscribe(data => {
            if (data.clientID === 0) {
                data.clientID = +this.route.snapshot.queryParams["parentId"];
            }
            this.model = data;
        },); // Subscription

    this.lookupService.getList("clients").then(data => {
        this.clients = data;
    }); // Promise
}

On the client-side, I need to make another server call, but only when I have data from both of the calls above. In other words, I need the Subscription to complete (well, not complete but set the value) and the Promise to complete.

Is there something like a Promise.all that would work to also ensure this.model has been set in the Subscription call?

EDIT: I could run these in series, but for performance reasons, I want to run them in parallel.

EDIT 2: The Promise was intended to load lookup data to populate a dropdown only once. The Subscription was intended to change the main model on each change of "id" in the URL .

  1. Use .zip() on the promise and the model-fetching observable. It will output an array of results that you can use to populate local class properties. At this point you can call your 3rd function (the local filter). Once the promise completes, so will .zip , so this chain has only one output.

  2. Once .zip() completes, listen to new route parameters and fetch corresponding models. As they arrive, set your local class property and run your local filter

  3. Subscribe to trigger the whole chain.

     ngOnInit(){ // Will run getOne() with every new parameter let getModelForParam = this.route.paramMap.switchMap( params => this.service.getOne(+params.get('id')) ).share(); // Zip will wait for both below to produce, then output an array of results // and complete (since getList() promise completes after one call) Observable.zip( this.lookupService.getList('clients'), getModelForParam ).do(results => { // capture results in order of .zip() arguments this.clients = results[0]; this.model = results[1]; this.localFilter();// call the filter }).concat( // this part executes once .zip() completes getModelForParam // continue fetching models for new params ).subscribe(model => { this.model = model; this.localFilter(); }) } 

Live demo

You can use Observable.forkJoin , which is equivalent to Promise.all .

Observable.forkJoin(this.route.paramMap
        .switchMap((params: ParamMap) => {
            var id = +params.get('id');
            return this.service.getOne(id);
        }), Observable.fromPromise(this.lookupService.getList("clients")))
        .subscribe((arrayOfResults) => {
             [firstCallResult, secondCallResult] = arrayOfResults;
             this.model = firstCallResult;
        });

EDIT:

To fulfill the part about updating parameters, we can use the Observable.combineLatest operator:

About Observable.combineLatest

Since it emits whenever one of the source observables emits, the subscribe block will be executed. Since the other observable is from a promise it will complete and not emit more values so this.lookupService.getList() will not be called again.

Observable.combineLatest(this.route.paramMap
            .switchMap((params: ParamMap) => {
                var id = +params.get('id');
                return this.service.getOne(id);
            }), Observable.fromPromise(this.lookupService.getList("clients")))
            .subscribe((arrayOfResults) => {
                 [firstCallResult, secondCallResult] = arrayOfResults;
                 this.model = firstCallResult;
                 // do whatever else is needed
            });

You can do something like

ngOnInit() {
  this.lookupService.getList("clients").then(data => {
    this.clients = data;
    this.route.paramMap
    .switchMap((params: ParamMap) => {
        var id = +params.get('id');
        return this.service.getOne(id);
    }).subscribe(data => {
        if (data.clientID === 0) {
            data.clientID = +this.route.snapshot.queryParams["parentId"];
        }
        this.model = data;
==>Call ur method here!!!
    },); /

}); // Promise

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM