角度内插值未在订阅时更新

Posted

技术标签:

【中文标题】角度内插值未在订阅时更新【英文标题】:Angular interpolated value not updating on subscription 【发布时间】:2019-01-12 10:10:24 【问题描述】: Angular 6.0.1 ngRx 6.0.1

我在视图中设置了一个插值:

firstName

当它绑定的字段的值发生变化时,它不会更新。但是,值 is 正在发生变化 - 如果我将其注销到订阅内的控制台,我会看到更新后的值。它只是不会在 UI 中更新。

以下是相关代码:

从我的组件订阅:

private subscribeToCurrentPerson(): void 
    this.tState$ = this.store
      .pipe(select(selectors.getCurrentPerson), takeWhile(() => this.componentActive))
      .subscribe((cp: Person) => 
        if (cp) 
          const name: string = cp.primaryName.value.parsedValue.givenNames[0];
          this.firstName = name;
          console.log('name: ' + name);  // <-- this shows correct new value
        
  );

subscribeToCurrentPerson 从组件的 ngOnInit 中调用。在此之前,firstName 属性是未定义的。

selectors.getCurrentPerson 选择器如下所示:

export const getCurrentPerson: MemoizedSelector<, Person> = 
    createSelector(getTState, (tState: ITState) => 
      console.log('selector: ', tState); // <-- this logs the correct new value
      return tState ? tState.currentPerson : null;
    );  

从选择器返回的currentPerson 值是一个新创建的对象。这是在应用程序的第一次运行时发生的,所以在此之前tState 是未定义的。

如果我在构造函数中注入ChangeDetectorRef 并在订阅中调用cdr.detectChanges(),UI 会更新。但在我看来,我通常不需要像这样使用ChangeDetectorRef,它应该“正常工作”。

我认为问题在于我的深层嵌套属性 (cp.primaryName.value.parsedValue.givenNames)。我从一个非 ngRx 项目继承了这些实体,但我认为下一步是尝试扁平化该结构,看看这是否让 ngRx 和 Angular 变化检测器更快乐。

我还有什么遗漏的吗?

更新

通过简单地更新订阅内我的组件上的本地属性,我已将深层嵌套的属性排除在外。所以subscribeToCurrentPerson 函数现在看起来像这样:

private subscribeToCurrentPerson(): void 
        this.tState$ = this.store
          .pipe(select(selectors.getCurrentPerson), takeWhile(() => this.componentActive))
          .subscribe((cp: Person) => 
            this.myProp = 'goodbye';
            this['newProp'] = 'world';
      );
    

myProp 是我为测试添加的组件上的现有属性。 newProp 不存在,直到它通过订阅内的括号表示法添加。结果如下:

myProp 没有更新 - 它显示了我在声明它时分配的值。但是,如果我在声明属性时未分配值,则订阅中分配的值会正确显示在 UI 中。 newProp 正确显示在 UI 中

我现在完全困惑了。 似乎一旦属性有了值,它就永远不会在 UI 中更新,即使值本身确实发生了变化(我可以通过在更新值后登录到控制台来判断)。

我没有为组件明确设置ChangeDetectionStrategy,所以它是Default

如果我打电话给detectChanges,一切正常,但我认为这没有必要。

【问题讨论】:

自从评论了你的previous question 并在stackblitz 中显示视图应该自动更新......我在自己的代码中遇到了和你一样的问题。 您的变更检测策略是什么?默认还是 onPush? 我都试过了,但目前是默认的。 听起来你是对的,就深度嵌套的属性而言。除了构造函数内的重新分配/嵌套属性之外,没有什么突出的代码在区域之外。毕竟,JS 自然不同意重嵌套的对象和子重新分配。抱歉,我无法提供更多帮助,也许其他人会看到我看不到的东西! NP,谢谢@Z.Bagley。我已经从图片中删除了深层嵌套的属性,现在对发生的事情完全感到困惑(请参阅上面的更新)。一旦属性具有值,就会阻止 UI 更新,但我不知道是什么。 【参考方案1】:

当父组件将其更改检测策略设置为OnPush 时,Angular 的更改检测机制将不会检查该父组件的组件树,尽管每次仍会调用该父组件及其子组件的 ngOnChanges 方法@Input 属性更改。要让 Angular 知道此树中的某些组件需要更新,请将 ChangeDetectorRef 注入该组件并使用其 API 通知 Angular 更新,例如 detectChangesmarkForCheck

【讨论】:

【参考方案2】:

很多时候来自组件的数据更新不会反映 html 模板。在这种情况下,您可以使用带有三元运算符的插值。

firstName ? firstName : ''

【讨论】:

以上是关于角度内插值未在订阅时更新的主要内容,如果未能解决你的问题,请参考以下文章

iOS 6 - 如何验证应用内可更新订阅?

关于应用内购买的问题:自动更新订阅

CloudKit 订阅未在 iOS10 上保存

iOS:应用内购买管理多个自动更新订阅,带有升级和降级选项

具有可更新订阅的 iOS 内容块扩展

Angular Jasmine 测试未在 ngOnInit 中触发订阅