<!DOCTYPE html>
<html>
  <head>
    <title>Angular 4 + TypeScript + zonejs => routing stops working after uncaught error</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css" integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi" crossorigin="anonymous">
    <link rel="stylesheet" href="styles.css">
    <script src="https://unpkg.com/zone.js@0.8.10?main=browser"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.9"></script>
    <script src="https://unpkg.com/systemjs@0.19.41/dist/system.src.js"></script>
    <script src="https://unpkg.com/typescript@2.1.4/lib/typescript.js"></script>
    <script src="config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>

  <body>
    <app></app>
  </body>

</html>
# Angular 4 + TypeScript + zonejs => routing stops working after uncaught error
import { Component } from '@angular/core';

@Component({
  selector: 'app',
  templateUrl: './app/app.html'
})
export class AppComponent {}
import { ErrorHandler, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule, Routes } from '@angular/router';
import { APP_BASE_HREF } from '@angular/common';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { ExampleFormComponent } from './forms/example-form.component';

import { ZoneListener } from 'app/zone.listener';

const appRoutes: Routes = [
  { path: 'forms', component: ExampleFormComponent },
  { path: '', component: HomeComponent }
];

export class MyErrorHandler implements ErrorHandler {
  handleError(error: any): void {
    console.log('MyErrorHandler: ' + error);
    throw error;
  }
}

export function MyRouterErrorHandler(error: any) {
  console.log('RouterErrorHandler: ' + error);
  throw error;
}

@NgModule({
  imports: [
    BrowserModule,
    RouterModule.forRoot(appRoutes, {
      errorHandler: MyRouterErrorHandler,
      enableTracing: true
  })
  ],
  declarations: [
    AppComponent,
    HomeComponent,
    ExampleFormComponent,
  ],
  providers: [
    { provide: ErrorHandler, useClass: MyErrorHandler},
    ZoneListener,
    { provide: APP_BASE_HREF, useValue: location.pathname }, // This is specifically for Plunker's baseURL: run.plunkr.co
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { 
  constructor(private $zoneListener: ZoneListener) {
  }
  
}

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

<nav class="navbar navbar-light bg-faded">
  <ul class="nav navbar-nav">
    <li class="nav-item">
      <a class="nav-link" routerLink="/">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" routerLink="/forms">Example Component</a>
    </li>
  </ul>
</nav>

<main class='container'>
  <router-outlet></router-outlet>
</main>
import { Component } from '@angular/core';

@Component({
  selector: 'example-form',
  template: `<div>Component</div>`
  
})
export class ExampleFormComponent implements OnInit {

  constructor() {
    
  }
  
  ngOnInit() {
    throw new Error("critical error during initialization");
  }
  
  submitRegistration(value: Object): void {
    console.log(value);
  }

}
app {
  .error {
    color: #FF4500;
    font-size: small;
  }
}
import { Component } from '@angular/core';

@Component({
  selector: 'home',
  directives: [],
  template: `<div>Home</div>`
})
export class HomeComponent {}
System.config({
  transpiler: 'typescript',
  typescriptOptions: {
    emitDecoratorMetadata: true,
    experimentalDecorators: true
  },
  map: {
    app: "./app",

    '@angular/core': 'npm:@angular/core@4.0.0/bundles/core.umd.js',
    '@angular/common': 'npm:@angular/common@4.0.0/bundles/common.umd.js',
    '@angular/compiler': 'npm:@angular/compiler@4.0.0/bundles/compiler.umd.js',
    '@angular/platform-browser': 'npm:@angular/platform-browser@4.0.0/bundles/platform-browser.umd.js',
    '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@4.0.0/bundles/platform-browser-dynamic.umd.js',
    '@angular/http': 'npm:@angular/http@4.0.0/bundles/http.umd.js',
    '@angular/router': 'npm:@angular/router@4.0.0/bundles/router.umd.js',
    '@angular/forms': 'npm:@angular/forms@4.0.0/bundles/forms.umd.js',
    '@angular/animations': 'npm:@angular/animations@4.0.0/bundles/animations.umd.js',

    'rxjs': 'npm:rxjs@5.1.0',
    'lodash': 'npm:lodash@4.17.4/'
  },
  //packages defines our app package
  packages: {
    app: {
      main: './main.ts',
      defaultExtension: 'ts'

    },
    rxjs: {
      defaultExtension: 'js'
    },
    lodash: {
      defaultExtension: 'js'
    }
  },
  paths: {
    'npm:': 'https://unpkg.com/'
  }
});
import {Injectable, NgZone} from '@angular/core';

@Injectable()
export class ZoneListener {
  constructor(private ngZone: NgZone) {
    this.ngZone.onStable.subscribe(this.onZoneStable);
    this.ngZone.onUnstable.subscribe(this.onZoneUnstable);
    this.ngZone.onError.subscribe(this.onZoneError);
  }

  onZoneStable() {
    console.log('ZoneListener: We are stable');
  }

  onZoneUnstable() {
    console.log('ZoneListener: We are unstable');
  }

  onZoneError(error) {
    console.error('ZoneListener: Error', error instanceof Error ? error.message : error.toString());
  }
}