【问题标题】:Angular/Rxjs how to subscribe to a function in a loop with different parametersAngular / Rxjs如何在具有不同参数的循环中订阅函数
【发布时间】:2020-11-15 12:36:41
【问题描述】:

如何调用在循环(管道 -> 映射)中返回可观察对象(主题)的函数?函数的参数每次都不一样。

我试着用一个例子来解释:

export class MyClass implements OnInit {

  private keyFigureSubject = new Subject();
  keyFigures$ = this.keyFigureSubject.asObservable();

  load() {
    const clients$ = of([{ id: 1, name: 'Mustermann' }, { id: 2, name: 'Hans Dampf' }, { id: 3, name: 'Pleite AG' }]);
      const result = clients$.pipe(
      flatMap((clients)=> clients),
      map(client => this.loadKeyfigures(client.id)) // this isnt working 
    );

    result.subscribe(x=>console.log(x));
  }

  loadKeyfigures(clientId: number) {

    // EDIT: This is a http call in "real life"

    const keyFigures = [];
    keyFigures.push({clientId: 1, name: 'A', value: 23});
    keyFigures.push({clientId: 1, name: 'B', value: 22});
    keyFigures.push({clientId: 2, name: 'A', value: 12});
    keyFigures.push({clientId: 3, name: 'A', value: 312});
    keyFigures.push({clientId: 3, name: 'B', value: 12333});
    keyFigures.push({clientId: 3, name: 'C', value: 4567});
    keyFigures.push({clientId: 3, name: 'D', value: 54});
    keyFigures.push({clientId: 4, name: 'A', value: 5672});
    keyFigures.push({clientId: 5, name: 'A', value: 243});
    keyFigures.push({clientId: 6, name: 'A', value: 334});

    keyFigures.forEach(keyFigure =>{
      if(keyFigure.clientId === clientId){
        this.keyFigureSubject.next(keyFigure);
      }
    });
    return this.keyFigureSubject.asObservable();

  }

}

最后我想要一个类似的列表:

Client 1; Keyfigure A; 23
Client 1; Keyfigure B, 22

问题似乎是在调用返回subject.asObservable() 之前调用了subject.next()。如果我订阅该属性,我将无法传递参数。

【问题讨论】:

    标签: angular typescript rxjs


    【解决方案1】:

    看起来您只需要为每个对loadKeyfigures 的新调用订阅一个内部可观察对象。为此,您只需将map 更改为mergeMap。这里没有真正的循环。您只是将流中的每个值都转换为 http 调用。

    load() {
      from([
        { id: 1, name: 'Mustermann' }, 
        { id: 2, name: 'Hans Dampf' }, 
        { id: 3, name: 'Pleite AG' }
      ]).pipe(
        mergeMap(client => this.loadKeyfigures(client.id))
      ).subscribe(console.log);
    }
    

    另外,值得注意的是,您的虚拟 http 调用不起作用。主题是“热”的可观察对象,因此当您将其作为可观察对象返回时,它不会再发出值了。

    试试这个:

    loadKeyfigures(clientId: number) {
    
      // EDIT: This is a http call in "real life"
    
      const keyFigures = [];
      keyFigures.push({clientId: 1, name: 'A', value: 23});
      keyFigures.push({clientId: 1, name: 'B', value: 22});
      keyFigures.push({clientId: 2, name: 'A', value: 12});
      keyFigures.push({clientId: 3, name: 'A', value: 312});
      keyFigures.push({clientId: 3, name: 'B', value: 12333});
      keyFigures.push({clientId: 3, name: 'C', value: 4567});
      keyFigures.push({clientId: 3, name: 'D', value: 54});
      keyFigures.push({clientId: 4, name: 'A', value: 5672});
      keyFigures.push({clientId: 5, name: 'A', value: 243});
      keyFigures.push({clientId: 6, name: 'A', value: 334});
    
      // Use from to convert array to a stream
      return from(keyFigures.filter(fig => 
        fig.clientId === clientId
      ));
    }
    

    【讨论】:

      【解决方案2】:

      你可以使用forkJoin和switchMap的组合:

      import { forkJoin } from "rxjs";
      import { switchMap } from "rxjs/operators";
      
      ...
      switchMap(client => forkJoin(this.loadKeyfigures(client.id)))
      

      在订阅方法中,您将收到每个可观察对象发出的值的列表。

      对于您的具体情况,但我不明白,为什么您需要从您的方法 loadKeyfigures 返回 Observables。您也可以只同步返回值。

      loadKeyfigures(clientId: number) {
          const keyFigures = [];
          keyFigures.push({clientId: 1, name: 'A', value: 23});
          keyFigures.push({clientId: 1, name: 'B', value: 22});
          keyFigures.push({clientId: 2, name: 'A', value: 12});
          keyFigures.push({clientId: 3, name: 'A', value: 312});
          keyFigures.push({clientId: 3, name: 'B', value: 12333});
          keyFigures.push({clientId: 3, name: 'C', value: 4567});
          keyFigures.push({clientId: 3, name: 'D', value: 54});
          keyFigures.push({clientId: 4, name: 'A', value: 5672});
          keyFigures.push({clientId: 5, name: 'A', value: 243});
          keyFigures.push({clientId: 6, name: 'A', value: 334});
      
          // Just filter out the invalid keyFigures by comparing the ids.
          return this.keyFigures.filter(({clientId: id}) => id === clientId);
        }
      

      然后你可以像你的例子中那样只使用地图运算符。

      【讨论】:

      • 感谢您的回复。对不起,我描述错了。该函数执行 http get 调用。我想用主题来模拟http调用。
      【解决方案3】:

      您不需要 BehaviorSubject 进行模拟,只需使用 of

      keyFigures.forEach(keyFigure =>{
            if(keyFigure.clientId === clientId){
              return of(keyFigure);
            }
          });
      

      还请注意,您需要像switchMap 这样的高阶运算符才能切换到另一个可观察值。

      switchMap(client => this.loadKeyfigures(client.id))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-06
        • 1970-01-01
        • 1970-01-01
        • 2021-11-04
        • 2021-12-19
        • 1970-01-01
        • 2016-10-17
        相关资源
        最近更新 更多