如何延迟对角度子组件的API调用?

时间:2018-09-18 14:49:05

标签: angular rxjs

我有一个组件,上面有2个子组件,父组件从URL获取参数进行一些计算并在模板上显示一些数据。

但是我还使用URL参数通过子组件上的@Input()传递给2个子组件。

我正在尝试寻找一个问题的解决方案,该问题可以在用户将所有数据加载到子组件之前查看用户是否导航。

因此,当用户导航到父组件时,我获得了其在URL上传递的ID,并调用API向用户显示一些数据。同时,我将该ID传递给调用另一个API并提取更多数据的子组件。

问题在于,用户可以在父组件显示上单击链接并更改URL上的ID,这将根据URL ID加载新数据,然后将其再次传递给子组件,这将导致它可以从API中提取新数据集。如果在所有数据从API调用返回之前单击快速,您会注意到子组件上的第一个API调用仍在进行,而第二个调用已启动。

所以发生的是,您将看到显示的第一个API数据,并且在第二次调用完成之后,数据将在子组件上使用新数据集进行更新。

防止这种情况发生的最佳方法是什么?我应该在子API调用中添加延迟吗?

3 个答案:

答案 0 :(得分:1)

听起来您已经让父母通过更改ID来更新孩子。

如果让孩子将其@Input视为Observable,那么如果传入ID在HTTP请求之前发生更改,则可以利用switchMap自动取消挂起的HTTP请求完成。

您可以通过以下方式实现此目标:

  1. 在子级中设置一个私有Subject实例来保存ID,
  2. 使用ngOnChanges使Subject的ID更改保持更新,
  3. 根据当前ID通过Subject传递Observable(作为switchMap)以获取HTTP请求Observable,并且
  4. 订阅该Observable,对响应执行任何工作。

以下(未经测试的)代码应接近您的需求:

private id: Subject = new BehaviorSubject(null);
private data: Observable;
private sub: Subscription;

ngOnChanges(changes: SimpleChanges) {
    if (changes['id']) {
        this.id.next(changes['id']);
    }
}

ngOnInit() {
    this.data = this.id.asObservable().pipe(
        filter(id => id !== null),
        switchMap(id => GET_RESPONSE_OBSERVABLE_FOR(id)),
        map(response => {
            // build & return data structure suitable for template
        })
    );
    this.sub = this.data.subscribe(data => {
        // update child according to data
    });
}

ngOnDestroy() {
    this.sub.unsubscribe();
}

如果您可以使用async管道订阅模板中的可观察对象,那么您甚至不需要在ngOnDestroy时手动退订。

这种方法消除了对任何硬编码延迟的需求。

答案 1 :(得分:0)

答案 2 :(得分:0)

在这种情况下,您可以做什么。将子项输入为Observable。 父级完成数据加载后,向子级发出{id}。

父组件

@Input() ID: string;
public id$: Observable<string>;

ngOnInit(){
   this.httpService.get('urltofetchdatawith{ID}')
    .subscribe(data =>{
        if(data){
           // After fetching the data in parent emit the {id} to child
           this.id$ = new Observable<string>(ob => ob.next(this.ID));
        }
    })
}

父组件模板

<child-component [id]="id$"> </child-component>

子组件

@Input() id: Observable<string>;

ngOnChanges(){
   if(id){
      this.id
        .pipe(
           map(value => value),
           switchMap(value => this.httpService('urltofetchdata{value}'))
        )
        .subscribe(data =>{
            // Child data
        })
   }
}