在角区外触发的导航,您是否忘记调用‘ ngZone. run()’?

我正在使用 Angular 7,并且在登录后面临一个问题 = > ,API GET 调用成功,组件也接收数据,但是 UI 没有显示那些数据。

当我打开浏览器控制台时,数据立即在 UI 中填充,并且控制台中显示一个警告。

“ core.js: 15686导航在角区外触发,是否忘记调用‘ ngZone.run ()’?”

我在谷歌上搜索了这个警告,发现了一些类似 this.ngZone.run()的变通方法,并在其中调用了我的 API。

但问题是,我使用了40多个组件,并在每个组件中调用了如此多的 API。因此,我必须在每个 API 调用中调用 ngZone.run(),这似乎很难做到。

请告诉我解决这个问题的更好的办法。 先谢谢你。

应用程序组件

getEmployees(): void {
this.employeeService.getEmployees().subscribe(e => {
this.employees = e;
});
}

应用服务

@Injectable()
export class EmployeeService {
constructor(private httpClient: HttpClient) { }


getEmployees() {
return this.httpClient.get<EmployeeModel[]>('employees');
}
77521 次浏览

通常,当您在一些外部 js 回调(来自与角度代码无关的外部 JavaScript)中包装角度调用时,会发生这种情况。

例子 app.component.ts:

callMyCustomJsLibrary() {
googleSdk.getLocations(location => this.getEmployees());
}


getEmployees(): void {
this.employeeService.getEmployees().subscribe(e => {
this.employees = e;
});
}

在这种情况下,您必须将调用包含到 NgZone 中,例如: this.ngZone.run(() => this.getEmployees());

The app.component.ts would then look like the following:

callMyCustomJsLibrary() {
googleSdk.getLocations(location => this.ngZone.run(() => this.getEmployees()));
}


getEmployees(): void {
this.employeeService.getEmployees().subscribe(e => {
this.employees = e;
});
}

If I talk from top then the meaning of this warning is that the event is triggered outside of zone. Angular uses 区域, also called 执行上下文 for 变化检测和 UI 渲染. So while 导航, Angular expects to re-renderer the UI but it is not happening here. That's the problem you are facing. So it throws this warning because Angular is processing the change detection and UI rendering when the code executed lies inside of Angular zone.

But actually, this warning comes when you are trying to call the router navigation inside the 订阅 method.

如果您将 路由器导航路由器导航调用放在 subscribe方法之外,那么它将不会再次抛出此警告,并且您将在导航后看到预期的 UI。

For more information about zones, read and watch the videos mentioned below:

Https://blog.thoughtram.io/angular/2017/02/21/using-zones-in-angular-for-better-performance.html#running-outside-angulars-zone

Https://www.youtube.com/watch?v=3iqtmusce_u&t=150

如果您尝试注入一个定制的服务,就会发生这种情况:

constructor(private myService: MyService) {
}

而忘记在模块配置中提供它:

@NgModule({
providers: [
MyService
]

我通过在 ngZone 中包装路由器导航命令修复了这个问题。请检查下面的代码

在构造函数中添加“ private zone: NgZone”。

private zone: NgZone


this.zone.run(() => {
this.router.navigate(['/login']);
});

我也有同样的问题,这对我有用,你有两种方法:

表格一:

document.location.href=`/component/${param}/...`

这样做的问题是,它将重新加载整个应用程序,这将使它变慢

第二种方法:

导入这个

import { Router } from '@angular/router';
import { Component, NgZone } from '@angular/core';

建造商:

 constructor(private _ngZone: NgZone, private _router: Router) { }




goTo(comp, param){
this._ngZone.run(()=>{
this._router.navigate([comp, param])
});
}

因此,当您想要转到组件时,简单地说:

this.goTo("/myComponent", "my-param-value");

希望对你有用

工作解决方案-修复

 ngAfterViewInit(): void {
let self = this;
this.platform.backButton.subscribe(() => {
console.log("back preseed \n \n");


self._ngZone.runOutsideAngular(() => {
setTimeout(() => {
self.Router.navigateByUrl("/stock-management");
}, 100);
});
});
}

在我的例子中,问题是由一个调用路由器的测试触发的,这个测试是为了确保被测组件对路由更改做出正确的反应。我测试中的代码大致如下:

const router: Router = TestBed.inject(Router);
await router.navigateByUrl('some-route');

注入 NgZone 并包装路由器调用是解决方案

const router: Router = TestBed.inject(Router);
const ngZone: NgZone = TestBed.inject(NgZone);
await ngZone.run(async () => router.navigateByUrl('some-route'));

This is also needed if you directly test a component method that triggers a navigation:

const ngZone: NgZone = ngZone = TestBed.inject(NgZone);
ngZone.run(() => component.someMethod()); // someMethod() triggers a router navigation