Resetting Angular 2 App

I ended up figuring this out in the end. This could be done more simply than my implementation, but I wanted to keep the bootstrapping in main.ts rather than stick it in the service that requests the restart.

  1. Create a singleton that provides a way for Angular and non-Angular (main.ts) to communicate:

boot-control.ts:

import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
export class BootController {
  private static instance: BootController;
  private _reboot: Subject<boolean> = new Subject();
  private reboot$ = this._reboot.asObservable();

  static getbootControl() {
    if (!BootController.instance) {
      BootController.instance = new BootController();
    }
    return BootController.instance;
  }

  public watchReboot() {
    return this.reboot$;
  }

  public restart() {
    this._reboot.next(true);
  }
}
  1. Adjust main.ts to subscribe to the reboot request:

main.ts:

import { enableProdMode, NgModuleRef, NgModule } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { BootController } from './boot-control';

if (environment.production) {
  enableProdMode();
}

const init = () => {
  platformBrowserDynamic().bootstrapModule(AppModule)
  .then(() => (<any>window).appBootstrap && (<any>window).appBootstrap())
  .catch(err => console.error('NG Bootstrap Error =>', err));
}

// Init on first load
init();

// Init on reboot request
const boot = BootController.getbootControl().watchReboot().subscribe(() => init());
  1. Add NgZone to the service that triggers the logout:

user-auth.service.ts:

import { BootController } from '@app/../boot-control';
import { Injectable, NgZone } from '@angular/core';

@Injectable()
export class UserAuthenticationService {
    constructor (
        private ngZone: NgZone,
        private router: Router
    ) {...}

    logout() {
        // Removes auth token kept in local storage (not strictly relevant to this demo)
        this.removeAuthToken();

        // Triggers the reboot in main.ts        
        this.ngZone.runOutsideAngular(() => BootController.getbootControl().restart());

        // Navigate back to login
        this.router.navigate(['login']);
    }
}

The NgZone requirement is to avoid the error:

Expected to not be in Angular Zone, but it is!


I came across the same issue. A simpler way is to use location.reload()

The function in your App.component which is called when the user clicks the logout button should look like this.

logout() {
  //Auth Logout service call
  this.auth.logout();
  //Router Navigation to Login Page
  this.router.navigate(['login']);
  //Reload Angular to refresh components and prevent old data from loading up for a 
  //another user after login. This especially applies lazy loading cases. 
  location.reload(); 
}