RxJS动态分配按钮的多个订阅

时间:2017-05-26 17:34:20

标签: angular rxjs observable angular2-observables

假设我有一个角度2组件,如下所示:

import { Component, AfterViewInit, ViewChildren, QueryList, ElementRef } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import {ApiService} from './my.service'
@Component({
  selector: 'my-component',
  template: `
    <div class='button0' [ngClass]="{selected: selection === 0}" #button>Hello World</div>
    <div class='button1'  [ngClass]="{selected: selection === 1}" #button>Hello World</div>
  `,
  styles: [`
  .selected {
    color: red;
  }
  `],
  providers: [ApiService]
})
export class MyComponent implements AfterViewInit { 
  selection = 0;
  @ViewChildren('button') buttons: QueryList<ElementRef>;
  buttonObservables:any[] = null;

  constructor(private api: ApiService) {}

  updateServer(index) {
    api.requestsExample(index)
      .then((result) => {
        //update other divs and stuff
      }
  }


  updateColor(index) {
    this.selection = index;
  }

  ngAfterViewInit () {
    this.buttonObservables = this.buttons.map((button) => Observable
      .fromEvent<MouseEvent>(button.nativeElement, 'click'));

    this.buttonObservables.map((observable) => {
      observable.throttleTime(2000).subscribe((event:MouseEvent) => {
          const element:Element = event.target as Element;
        this.updateServer(element.classList[1].match(/\d+/g));
      })
    });

    this.buttonObservables.map((observable) => {
      observable.subscribe((event:MouseEvent) => {
        const element:Element = event.target as Element;
        this.updateColor(element.classList[1].match(/\d+/g));
      })
    });
  }
}

其中ApiService.requestsExample

是一个异步注释函数,它发出请求并返回响应。

关于工作的代码(例如请求被限制,按钮混合不会导致请求太多,颜色仍然会改变)

我正在努力想办法处理下面的边框: 1)我想保证最后触发的结果是接受响应的结果(假设响应返回),然后按时间顺序返回。由于请求是异步的,我不确定如何实现这一点? 2)(推论)为了防止更新闪烁,我还想放弃一旦后来的结果返回时从服务器返回的任何结果(基于问题顺序而不是响应顺序)。 3)一旦最后一个当前的实时请求返回,我想丢弃所有正在进行的观察,因为我不再关心它们。

所以基本上,如果用户将两个按钮混合20秒,我会期望发出10个请求,但除了切换按钮颜色外,更新UI一次,并更新到正确的值。

此外,我很想知道是否有更好的方法可以通过Observables实现这一结果(或者即使可观察对象是这项工作的正确工具!)

1 个答案:

答案 0 :(得分:2)

让我们解释下面的RxJS 5示例:

  • 你想让updateServer成为反应计算的一部分,所以你让它返回一个可观察的。
  • 由于您以相同的方式处理所有点击,因此mergeAll来自不同按钮的所有点击都是有意义的。
  • 由于您只是使用按钮的索引进行计算,因此map点击就可以了。
  • 您可以使用updateColor作为副作用立即执行do
  • debounceTime(1000)仅在传递一秒后发出点击而没有其他点击。我认为这比Throttle好,因为如果用户进行多次快速点击,您就不想进行不必要的网络通话。只有最后一个。
  • 由于您希望在新点击时取消之前的updateServer,因此使用switchMap是有意义的。它将点击映射到新的updateServer可观察对象然后中止它,并在新点击到达时切换到新的点击。
  • 由于您希望忽略第一个updateServer之后的所有进一步点击,或者这是我理解的方式3),take(1)将获得一个结果,然后完成整个链。
updateServer(index) {
  return Observable.fromPromise(api.requestsExample(index))
}

this
  .buttonObservables
  .mergeAll()
  .map(ev => ev.target.classList[1].match(/\d+/g))
  .do(idx => this.updateColor(idx))
  .debounceTime(1000)
  .switchMap(idx => this.updateServer(idx))
  .take(1)
  .subscribe(result => {
    // update other divs
  })