最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to call a function after the completion of two Angular 2 subscriptions? - Stack Overflow

programmeradmin3浏览0评论

I am on Angular 2.3.1 and I am fairly new to both Angular and event based programming. I have two subscriptions, route.params.subscribe and engineService.getEngines(). In my onInit I want to call getEngineName after this.route.params.subscribe and this.engineService.getEngines().subscribe plete.

Reason for this: getEngineName functions depends on the engineId from the queryParams and the engines array which is populated after the pletion of getEngines() call.

I did look at flatMap and switchMap but I did not pletely understand them.

This is the code in the ponent:

export class ItemListComponent implements OnInit {
  items: Item[];

  engines: Engine[];
  private engineId: number;

  constructor(
    private router: Router,
    private route: ActivatedRoute,
    private itemService: ItemService,
    private engineService: EngineService
   ) {}

  ngOnInit() {
    this.route.params.subscribe((params: Params) => {
      this.engineId = +params['engineId'];

      // itemService is irrelevant to this question 
      this.itemService.getItems({engineId: this.engineId})
        .subscribe((items: Item[]) => {
          this.items = items;
        });
    });

    this.engineService.getEngines()
      .subscribe(engines => this.engines = engines);

    // This should only run after engineId and engines array have been populated.
    this.getEngineName(this.engineId);
  }

  getEngineName(engineId: number) {
    this.engines.find((engine) => {
      return engine.id === engineId;
    })
  }
}

I am on Angular 2.3.1 and I am fairly new to both Angular and event based programming. I have two subscriptions, route.params.subscribe and engineService.getEngines(). In my onInit I want to call getEngineName after this.route.params.subscribe and this.engineService.getEngines().subscribe plete.

Reason for this: getEngineName functions depends on the engineId from the queryParams and the engines array which is populated after the pletion of getEngines() call.

I did look at flatMap and switchMap but I did not pletely understand them.

This is the code in the ponent:

export class ItemListComponent implements OnInit {
  items: Item[];

  engines: Engine[];
  private engineId: number;

  constructor(
    private router: Router,
    private route: ActivatedRoute,
    private itemService: ItemService,
    private engineService: EngineService
   ) {}

  ngOnInit() {
    this.route.params.subscribe((params: Params) => {
      this.engineId = +params['engineId'];

      // itemService is irrelevant to this question 
      this.itemService.getItems({engineId: this.engineId})
        .subscribe((items: Item[]) => {
          this.items = items;
        });
    });

    this.engineService.getEngines()
      .subscribe(engines => this.engines = engines);

    // This should only run after engineId and engines array have been populated.
    this.getEngineName(this.engineId);
  }

  getEngineName(engineId: number) {
    this.engines.find((engine) => {
      return engine.id === engineId;
    })
  }
}

Share Improve this question edited Jan 9, 2017 at 20:34 eko 40.7k11 gold badges78 silver badges101 bronze badges asked Jan 9, 2017 at 20:17 YathiYathi 1,0611 gold badge14 silver badges21 bronze badges 1
  • you could use bineLatest. Your problem is similar to this one: stackoverflow./questions/40872357/… With bineLatest you don't need to nest subscriptions. – chrigu Commented Jan 9, 2017 at 20:32
Add a ment  | 

2 Answers 2

Reset to default 4

Why don't you just move the logic inside the route.params callback?

this.route.params.subscribe((params: Params) => {
      this.engineId = +params['engineId'];

      // itemService is irrelevant to this question 
      this.itemService.getItems({engineId: this.engineId})
        .subscribe((items: Item[]) => {
          this.items = items;
        });

     //this.engineId is defined here (1)
     this.engineService.getEngines()
      .subscribe((engines) => {
         this.engines = engines;
         //this.engines is defined here (2)
         this.getEngineName(this.engineId);
     });
});

with flatMap and forkJoin:

this.route.params.flatMap((params: Params) => {
      this.engineId = +params['engineId'];    

      return Observable.forkJoin( 
         this.itemService.getItems({engineId: this.engineId}),
         this.engineService.getEngines()
      )          
}).subscribe((data)=>{
   let items = data[0];
   let engines = data[1];
   this.items = items;
   this.engines = engines;
   this.getEngineName(this.engineId);
});

switchMap is remended in this scenario.

    this.route.params.pluck('engineId') //pluck will select engineId key from params
        .switchMap(engineId => {
            this.getItems(engineId);
            return this.engineService.getEngines().map(engines => {
                /*this.engineService.getEngines() emits the list of engines.
                  Then use map operator to convert the list of engines to engine we are looking for
                 */
                return engines.find((engine) => {
                    return engine.id === engineId;
                })
            })
        }).subscribe(engine => {
          //engine  
    })

    getItems(engineId) {
      this.itemService.getItems({engineId: engineId})
        .subscribe((items: Item[]) => {
          this.items = items;
        });
    }

Suppose the engineId in the params changes, the first observable this.route.params.pluck('engineId') will emit data, which will cause the next observable this.engineService.getEngines() to get fired. Now suppose the route changes before this observable emits the data. Here you need to cancel getEngines observable to prevent error. This is done by switchMap.

switchMap cancels inner observable if outer observable is fired.

PS: I have avoided keeping any states like this.engineId etc.

发布评论

评论列表(0)

  1. 暂无评论