【问题标题】:Angular changeDetector.detectChanges() breaks matTooltip in *ngForAngular changeDetector.detectChanges() 在 *ngFor 中破坏 matTooltip
【发布时间】:2020-12-03 06:56:11
【问题描述】:

以下组件中的 matTooltip 正确重绘。工具提示的覆盖层和小气泡被渲染,但文本丢失(尽管在浏览器中检查时在 html 中)并且定位不正确。

有趣的是,工具提示在我删除 detectChanges() 调用时有效,或者它在 *ngFor 之外有效,即使使用 detectChanges();

@Component({
  selector: 'mur-app-titlebar',
  templateUrl: './app-titlebar.component.html',
  styleUrls: ['./app-titlebar.component.scss']
})
export class AppTitlebarComponent implements OnInit, OnDestroy {
  public appbarItems: IMenuItem[];

  private destroy$ = new Subject();

  constructor(
    private appBarService: AppBarService, // my custom service
    private changeDetector: ChangeDetectorRef,
  ) {
  }

  public ngOnInit() {
    this.appBarService.getAppbarItems().pipe( //observable comes from outside of angular
      takeUntil(this.destroy$)
    ).subscribe(value => {
      this.appbarItems = value || [];
      // change detection is not triggered automatically when the value is emmited
      this.changeDetector.detectChanges(); 
    });
  }

  public ngOnDestroy() {
    this.destroy$.next();
  }

}
<ng-container *ngFor="let item of appbarItems">
      <button mat-button
              (click)="item.onclick && item.onclick()"
              [disabled]="item.disabled"
              [matTooltip]="item.tooltip"
              [style.color]="item.color">
        <mat-icon *ngIf="item.icon"
                  [class.mr-3]="item.label">
          {{item.icon}}
        </mat-icon>
        <span>{{item.label}}</span>
      </button>
     
    </ng-container>

我已经验证,appbarItems 只设置了一次并且不会改变

【问题讨论】:

  • 这似乎是一个异步操作问题。将您的 ngFor 移动到按钮中,使用 *ngIf="appbarItems" 并删除 detectChanges 调用。或者将管道分配给属性并将其与async 管道一起使用
  • 您使用手动订阅而不是异步管道是否有特殊原因?
  • 能否在 stackblitz 中重现此问题?
  • 您确定没有在控制台中遇到任何其他错误吗?这似乎是由于某种原因渲染停止。还有 ++ 用于异步管道建议
  • 为什么没有触发变更检测?

标签: angular typescript angular-material angular-material-8


【解决方案1】:

通常你不需要在 Angular 的异步操作回调中调用 cdRef.detectChanges()

但是,如果您这样做,则意味着您正在尝试解决视图更新的一些问题。异步代码后组件视图未更新可能有多种原因:

  • 您的组件被隐藏以在 OnPush 更改检测策略下进行检查

  • 回调在 Angular 区域之外执行。

看起来您面临第二种情况。在 Angular 区域之外调用 cdRef.detectChanges 会给您带来一些 Angular 处理程序将在 Angular 区域之外注册的情况。因此,这些处理程序不会更新视图,您将在其他地方调用 detectChanges 或再次使用 zone.run。

以下是此类情况的示例https://ng-run.com/edit/XxjFjMXykUqRUC0irjXD?open=app%2Fapp.component.ts

您的解决方案可能是使用 ngZone.run 方法将代码执行返回到 Angular 区域:

import { NgZone } from '@angular/core';

constructor(private ngZone: NgZone) {}

.subscribe(value => {
  this.ngZone.run(() => this.appbarItems = value || []);
  

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-03
    • 2017-02-16
    • 2021-09-09
    • 1970-01-01
    • 2019-11-07
    • 2020-04-14
    • 1970-01-01
    • 2017-11-17
    相关资源
    最近更新 更多