【问题标题】:Resetting Angular 2 App重置 Angular 2 应用程序
【发布时间】:2017-04-05 14:40:36
【问题描述】:

我的 Angular 2 应用程序具有注销功能。如果可以,我们希望避免重新加载页面(即document.location.href = '/';),但注销过程需要重置应用程序,因此当另一个用户登录时,前一个会话中没有残留数据。

这是我们的 main.ts 文件:

import 'es6-shim/es6-shim';
import './polyfills';    
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { ComponentRef, enableProdMode } from '@angular/core';
import { environment } from '@environment';
import { AppModule } from './app/app.module';

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

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

init();

platformBrowserDynamic().onDestroy(() => {
  init();
});

您可以看到,当应用程序被销毁时,我正在尝试调用 init() 方法。我们的 user-authentication.service 中的 logout 方法发起了销毁:

logout() {   
  this.destroyAuthToken();  
  this.setLoggedIn(false);
  this.navigateToLogin()
  .then(() => {
    platformBrowserDynamic().destroy();
  });
}

这会产生以下错误:

选择器“app-root”没有匹配任何元素

任何帮助表示赞赏。

【问题讨论】:

  • 我想当你调用 platformBrowserDynamic() 你会得到一个新的平台。您可能需要在第一次调用时存储一个引用,然后在该引用上调用 destroy()。

标签: angular angular2-services


【解决方案1】:

我最终弄清楚了这一点。这可以比我的实现更简单,但我想将引导程序保留在 main.ts 中,而不是将其粘贴在请求重启的服务中。

  1. 创建一个单例,为 Angular 和非 Angular (main.ts) 提供一种通信方式:

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. 调整main.ts 订阅重启请求:

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. 将 NgZone 添加到触发注销的服务中:

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']);
    }
}

NgZone 的要求是为了避免错误:

预计不在 Angular Zone,但它是!

【讨论】:

  • 一段很棒的代码,效果很好。我认为对此的补充是添加一个注销屏幕 - 如果您在单击按钮时重新启动,整个应用程序会冻结 2-3 秒,这不是一个很好的用户体验。
  • 答案中的破坏部分在哪里?它出现在原始问题中,但随后消失了。你确定你没有内存泄漏问题吗?
  • 仍然适用于 Angular 8。在注销时清除用户数据的良好解决方案,但很大程度上取决于应用程序的大小。再次调用 appbootstrapModule 是一个代价高昂的函数。但在大多数中小型应用程序中,这可能会奏效。谢谢。
  • 在 Angular 10 中仍然有效。您能否解释一下它是如何工作的。我是 Angular 新手。
  • 这种方法有一个警告,每次应用程序重新启动时,所有 CSS 样式都会被克隆并附加到 HEAD 标记中。这将导致应用程序中出现一些奇怪的行为,至少在我的情况下是这样。
【解决方案2】:

我遇到了同样的问题。更简单的方法是使用 location.reload()

当用户单击注销按钮时调用的 App.component 中的函数应该如下所示。

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(); 
}

【讨论】:

  • 这对我不起作用。我总是得到问题对话框。不过只在 chrome 上测试过。
猜你喜欢
  • 2018-08-02
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多