如何检测 angular 中的模板是否发生错误?

How to detect if error happened in template in angular?

我正在 angular 中开发全局错误处理程序,我的项目的要求也是在错误时显示模态 window,以便用户可以报告是否有问题,我们可以修复它。除非模板中发生错误,否则它工作正常。在这种情况下,更改检测基本上被破坏了,它不更新绑定,因此 Material 模态对话框显示为空。我试着 google 并检查了 ngDebugContext 中的所有可用数据,但没有什么可以回答我的问题。要点是,万一模板中发生错误(或者我们可以知道更改检测是否通常已死),那么我将只显示警报。作为最后的解决方案,我将使用静态模板创建模态组件,其中文本将被硬编码并在出现任何未处理的错误时显示。

最后,我们通过使用更改检测被破坏的事实解决了它,并使用 angular 绑定 [hidden]='true' 在模态中创建了一个始终隐藏的元素,但是随着更改检测被破坏,它将被忽略,因此其中的文本将被显示,这样我们甚至可以在应用程序真正崩溃时显示非常具体的消息,如

<!-- This part is fallback for unhandled error which happens during change detection in the template -->
    <div class='crash-error-heading' [hidden]='true'>
      <h2>Something went really wrong</h2>
    </div>
<!---->

您可以像这样在全局级别定义自定义错误处理程序:

自定义错误-handler.service.ts

import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class CustomErrorHandler implements ErrorHandler {
  constructor() { }

  handleError(error) {
    // your custom error handling logic
    console.log('GLOBAL ERROR CAUGHT: ', error.toString())
  }
}

app.module.ts

import { NgModule, ErrorHandler } from '@angular/core';
import { CustomErrorHandler } from './custom-error-handler.service';

@NgModule({
  // ...
  providers: [
    {
      provide: ErrorHandler,
      useClass: CustomErrorHandler
    }
  ],
  // ...
})
export class AppModule { }

但是你不能用它来捕捉变量的拼写错误。这是有道理的。如果您采用以下组件:

TS

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  name = 'Angular 6';

  triggerError() {
    throw new Error('Some error');
  }
}

HTML

<!-- variable is defined as `name` but typo -->
<p>
  Name: {{ nam || 'Default name' }}
</p>

<button (click)="triggerError()">Trigger error caught by global/custom error handler</button>

这里我们进入渲染视图 "Default name" 因为 nam 只是未定义。这不是实际错误。尝试在浏览器控制台或 nodejs 上下文中写入 undefined,没问题。这不是错误。

也就是说,如果您尝试访问未定义对象上的 属性,则会出现错误。因此,如果您将 HTML 更新为:

<p>
  Name: {{ nam.someUndefinedProp || 'Default name' }}
</p>

您会注意到 CustomErrorHandler 发现了那个错误。

但一般来说,我不建议你这样做。它必须得到确认,但也许 AOT 可以捕获它,如果它不能捕获它,那么您应该编写一些集成或 E2E 测试来捕获它。

这是一个关于 stackblitz 的工作示例:

https://stackblitz.com/edit/angular-sipcki?file=src%2Fapp%2Fapp.component.html