Angular changeDetector.detectChanges() 在 *ngFor 中破坏 matTooltip
Angular changeDetector.detectChanges() breaks matTooltip in *ngFor
以下组件中的 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 只设置了一次并且没有改变
通常在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 || []);
以下组件中的 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 只设置了一次并且没有改变
通常在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 || []);