Angular OnPush:更新的输入字符串不会更新模板

Angular OnPush: an updated Input string won't update the template

有一个默认 changeDetection 的父组件和两个 onPush 更改检测策略的子组件。在更新输入变量时,模板不会更新。我不能在 ChildBComponent 中使用异步管道,因为它是项目的全局 UI 组件,重构不是一个选项。我该怎么做?

parent.ts

@Component({
   selector: 'parent',
   template: `
   <div>
     <child-a>
        <child-b [label]="firstLabel"></child-b>
        <child-b [label]="secondLabel"></child-b>
        <child-b label="Just a plain label"></child-b>
     </child-a>
   </div>`
})
export class ParentComponent implements OnInit {

   public ngOnInit(): void {
      this.httpService.loadData()
        .subscribe(data => {
           this.someValue = 1;
           this.otherValue = 2;
        });
   }

   // getters to explicitly trigger change detection
   public get firstLabel(): string {
     return `Something ${ this.someValue || '?'}`;
   }

   public get secondLabel(): string {
     return `Different ${ this.otherValue || '?'}`;
   }
}

子-a.ts

@Component({
   selector: 'child-a',
   template: `
      <div>Layout wrapper</div>
      <ng-content></ng-content>`,
   changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildBComponent implements AfterContentInit {
}

子-b.ts

@Component({
   selector: 'child-b',
   template: '<div>{{ label }}</div>',
   changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildBComponent implements AfterViewInit, OnDestroy {
   @Input public label: string;
}

我尝试将 @Input 转换为 getter/setter - 但无济于事。调试时,更改正在通过,但只有在我单击组件本身时模板才会更新。投入 markForCheck() 也无济于事。

想法很有帮助。

编辑:添加 StackBlitz。请使用广泛的预览来查看问题;奇迹般地,当显示移动视图元素时它可以正常工作。

问题不在于变更检测,标签值正确反映在 html 中。 countAcountB 值的变化确实反映在 HTML 中,只是 CSS 给人的印象好像 html 没有更新。

fieldtabs.component.html 中,您有通过 <ul> 显示标签的逻辑,并且您还有 <ng-content>.

问题是当设备的最大宽度为 767.98px 时,<ul *ngIf="!vertical" class="fieldtabs--tabs-container"> 元素不会显示为以下 CSS:

@media (max-width: 767.98px) {
  .fieldtabs--tabs-container {
      display:none
  }
}

<fieldtab> 即内容子项仅在设备最大宽度为 767.98px 时可见。下面是负责相同的CSS:

.fieldtabs-l {
  display: none
}

@media (max-width: 767.98px) {
  .fieldtabs-l {
      display:flex;
      align-items: center
  }
}

负责显示label的fieldtab模板html有上面的class:

<div *ngIf="!invisible" class="fieldtabs-l fieldtab--accord"

因此当设备最大宽度为 767.98px 时:

  • 您的 OnPush 内容子 fieldtab 模板中存在的 {{ label }} 插值可见
  • 您的 OnPush fieldtabs 模板中存在的 {{ tab.label }} 插值不可见

当宽度大于 767.98px 时,会发生相反的情况,即 {{ tab.label}} 是您在屏幕上看到的内容,它不会更新,因为 tabs 是在 [=29] 中构建的=] 并且当 countAcountB 被分配新值时不会再次调用该方法。