【问题标题】:How can I merge these two observables and remove the nested observable?如何合并这两个可观察对象并删除嵌套的可观察对象?
【发布时间】:2020-01-01 14:40:09
【问题描述】:

我正在努力理解如何合并两个可观察对象并利用它们的合并产品。我看过无数关于 mergeMap、switchMap、flatMap、大理石图等的视频,但我仍然不明白合并 observables 是如何工作的。我觉得在使用 RxJS 时我不会高效,甚至不会正确。

我有一个正在订阅的 observable,我还想订阅我的代码中特定表单数组的 valueChanges observable。但是,我需要确保仅在正确构建表单数组之后才进行第二次订阅,否则我会收到 null 错误。

显然,这样做是在我第一次订阅的下一个函数中订阅 valueChanges,但这是一种不好的做法,我想避免它。但是,我不确定应该以何种方式构建我的代码,以便在不使用嵌套订阅的情况下获得我想要的行为。

setSettings$(serial: string) {
    return this.getSettingsFromSerial$(serial).pipe(
      tap(val => {
        this.settingsState.savedSettingsState = val;
        this.settingsState.ipRestrictionEnabled = val.ipRestrictionSettings.ipRestrictionEnabled;
        if(val.ipRestrictionSettings.ipRanges.length === 0){
          this.addEmptyRange();
        }
        else
        {
          for (const i of val.ipRestrictionSettings.ipRanges) {
            this.addRange(i.startRange, i.endRange, i.label);
          }
        }
        this.settingsState.displaySettings = true;
        this.settingsState.displayForm = true;
        this.hideRangeErrorsUntilNotPristine(); <-- I need to merge (?) this with my first observable to ensure that it happens after the form is built.
      })
    );
  }

  // TODO :: Cancel this on destroy 
  hideRangeErrorsUntilNotPristine(){
    this.ipRangeFormArray.valueChanges.subscribe( res => {
      let formGroups = this.ipRangeFormArray.controls;

      for(let i = 0; i < formGroups.length; i++){
        if(formGroups[i].pristine === true) {
          this.settingsState.ipRangeValidStates[i].displayError = false;
        }
        else {
          this.settingsState.ipRangeValidStates[i].displayError = true;
        }
      }
    });
  }

【问题讨论】:

  • 您的 formarray 是从服务器获取 json 数据并需要创建它,还是您只是从您项目中存在的 json 配置数据生成 formarray?
  • 表单数组正在使用来自服务器的 json 数据生成
  • 如果你想等待一个 observable 发出值来触发第二个 observable,你可以使用concatMap。它确保在第一个发出值之后调用第二个。你可以看看这个interactive marble diagrams有一个更好的理解。
  • 因为这是一个建议。我不确定表单是否总是被创建,当他尝试订阅 valueChanges 时,因为这会导致未定义。通常我会使用 afterViewInit() 回调。
  • @sagat 不幸的是,在这种情况下 afterViewInit() 将不起作用,因为异步调用发生在对 afterViewInit 的调用之后

标签: angular rxjs


【解决方案1】:

据我了解,您需要做的就是确保在您的 TypeScript 代码中实例化 FormControl 对象后调用此方法。我选择mergeMap 并没有什么特别的原因,因为您只需要担心如果外部 Observable 多次发出,您需要使用哪个运算符。

setSettings$(serial: string) {
    return this.getSettingsFromSerial$(serial).pipe(
      tap(val => {
        this.settingsState.savedSettingsState = val;
        this.settingsState.ipRestrictionEnabled = val.ipRestrictionSettings.ipRestrictionEnabled;
        if(val.ipRestrictionSettings.ipRanges.length === 0){
          this.addEmptyRange();
        }
        else
        {
          for (const i of val.ipRestrictionSettings.ipRanges) {
            this.addRange(i.startRange, i.endRange, i.label);
          }
        }
        this.settingsState.displaySettings = true;
        this.settingsState.displayForm = true;
      }),
      // this gets called once everything in the `tap` has finished,
      // because everything is synchronous
      mergeMap(() => this.hideRangeErrorsUntilNotPristine())
    );
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 1970-01-01
    • 1970-01-01
    • 2023-01-25
    • 2020-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多