【问题标题】:Error while implementing CanDeactivate Guard实施 CanDeactivate Guard 时出错
【发布时间】:2019-06-15 12:07:16
【问题描述】:

我目前正在尝试为我的 Angular 应用程序实现 CanDeactivate Guard,该应用程序已经具有 HTTP 拦截器来解析身份验证。 但是添加 CanDeactivate 守卫会引发错误,如下所述。

我已经在 AppModule 的 providers 数组中注册了实现 CanDeactivate 接口的类。 我已经在路由的 canDeactivate 属性中注册了实现 CanDeactivate 接口的类。

实现 CanDeactivate 接口的类:

export interface CanComponentDeactivate {
  canComponentDeactivate(): boolean;
}

@Injectable({providedIn: 'root'})
export class AppRegisterDeactivateGuard implements CanDeactivate<AppRegisterComponent> {
  canDeactivate(
    component: AppRegisterComponent,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    return component.isDeactivated;
  }
}

应用了 Deactivate 防护的组件:

@Component({
  selector: 'app-app-register',
  templateUrl: './app-register.component.html',
  styleUrls: ['./app-register.component.css']
})
export class AppRegisterComponent implements OnInit, CanComponentDeactivate {
  isDeactivated = false;
  @ViewChild('registrationForm') registForm: NgForm;
.
.
canComponentDeactivate() {
    if (this.registForm.dirty) {
      this.isDeactivated = confirm('You have modified changes in the form. \nDo you still want to navigate away ? ');
    }
    return this.isDeactivated;
  }
}

该端点的路由定义:

...
{ path: 'register', component: AppRegisterComponent, canDeactivate: ['AppRegisterDeactivateGuard'] },

模块中的Providers数组:

 providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: AppAuthInterceptService,
    multi: true
  }, AppRegisterDeactivateGuard],
  bootstrap: [AppComponent]

错误

  StaticInjectorError(Platform: core)[AppRegisterDeactivateGuard]: 
    NullInjectorError: No provider for AppRegisterDeactivateGuard!
Error: StaticInjectorError(AppModule)[AppRegisterDeactivateGuard]: 
  StaticInjectorError(Platform: core)[AppRegisterDeactivateGuard]: 
    NullInjectorError: No provider for AppRegisterDeactivateGuard!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:8896)
    at resolveToken (core.js:9141)
    at tryResolveToken (core.js:9085)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:8982)
    at resolveToken (core.js:9141)
    at tryResolveToken (core.js:9085)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:8982)
    at resolveNgModuleDep (core.js:21218)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:21907)
    at getToken (router.js:2865)
    at resolvePromise (zone.js:831)
    at resolvePromise (zone.js:788)
    at zone.js:892
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17290)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
    at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:502)
    at invokeTask (zone.js:1744)

【问题讨论】:

    标签: angular angular-guards angular-httpclient-interceptors


    【解决方案1】:

    TLDR; 将您的路线更改为:

    { path: 'register', component: AppRegisterComponent, canDeactivate: [AppRegisterDeactivateGuard] }
    

    将您的提供者更改为:

    [{
        provide: HTTP_INTERCEPTORS,
        useClass: AppAuthInterceptService,
        multi: true
      }]
    

    更长的答案:

    AppRegisterDeactivateGuard 同时具有{providedIn: 'root'} 并将其声明为模块中的提供者是不必要的。 See the Angular provider docs.

    这里的问题是路由和提供者的组合。

    现在您的路由正在通过字符串名称查找令牌,但它可以通过类名获得。

    使用@Injectable({providedIn: 'root'}),你如何拥有它使用类名作为令牌,它将作为 AppRegisterDeactivateGuard 提供。

    在您的提供商中拥有AppRegisterDeactivateGuard,您如何拥有它将使其可用作 AppRegisterDeactivateGuard。

    我不推荐这样做,但是如果您想或需要通过字符串名称引用它,您可以将它放在提供程序中,如下所示:

    { provide: 'AppRegisterDeactivateGuard', useClass: AppRegisterDeactivateGuard }
    

    【讨论】:

    • 谢谢@OneLunchMan。将类注册为路由定义中的字符串是一个愚蠢的错误。将其更改为类名解决了它。我知道使用元数据和提供程序数组注册服务是不必要的,但我在调试时这样做只是为了确保它被注册。非常感谢!!
    【解决方案2】:

    你需要在泛型中传递接口:

    export class AppRegisterDeactivateGuard implements CanDeactivate<CanComponentDeactivate > {
    
    

    然后实现canDeactivate方法

    【讨论】:

      猜你喜欢
      • 2018-06-07
      • 2018-12-12
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多