TypeError: Cannot read property 'canDeactivate' of null

╄→гoц情女王★ 提交于 2020-07-22 05:31:10

问题


I'm trying to use the canDeactivate router guard. The component I'm passing in (ClaimsViewComponent) is null the first time the code runs. But on subsequent runs, the code runs as expected. We're trying to figure out why the component is null on first run.

This is the canDeactivate guard code:

@Injectable()
export class ConfirmDeactivateGuard implements 
CanDeactivate<ClaimsViewComponent> {
  canDeactivate(target: ClaimsViewComponent): boolean {

      if (target.canDeactivate()) {
          return window.confirm('Do you really want to cancel?');
      }

      return true;
  }
}

This is the routing module code:

const routes: Routes = [
{ path: ':type', component: ClaimsViewComponent, canDeactivate: 
[ConfirmDeactivateGuard] }
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})

Here is the full error stack:

TypeError: Cannot read property 'canDeactivate' of null
    at ConfirmDeactivateGuard.canDeactivate (confirm-deactivate-guard.ts:16)
    at MergeMapSubscriber.eval [as project] (router.js:3933)
    at MergeMapSubscriber._tryNext (mergeMap.js:128)
    at MergeMapSubscriber._next (mergeMap.js:118)
    at MergeMapSubscriber.Subscriber.next (Subscriber.js:95)
    at ArrayObservable._subscribe (ArrayObservable.js:116)
    at ArrayObservable.Observable._trySubscribe (Observable.js:172)
    at ArrayObservable.Observable.subscribe (Observable.js:160)
    at MergeMapOperator.call (mergeMap.js:92)
    at Observable.subscribe (Observable.js:157)
    at ConfirmDeactivateGuard.canDeactivate (confirm-deactivate-guard.ts:16)
    at MergeMapSubscriber.eval [as project] (router.js:3933)
    at MergeMapSubscriber._tryNext (mergeMap.js:128)
    at MergeMapSubscriber._next (mergeMap.js:118)
    at MergeMapSubscriber.Subscriber.next (Subscriber.js:95)
    at ArrayObservable._subscribe (ArrayObservable.js:116)
    at ArrayObservable.Observable._trySubscribe (Observable.js:172)
    at ArrayObservable.Observable.subscribe (Observable.js:160)
    at MergeMapOperator.call (mergeMap.js:92)
    at Observable.subscribe (Observable.js:157)
    at resolvePromise (zone.js:814)
    at resolvePromise (zone.js:771)
    at eval (zone.js:873)
    at ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:4740)
    at ZoneDelegate.invokeTask (zone.js:420)
    at Zone.runTask (zone.js:188)
    at drainMicroTaskQueue (zone.js:595)

Thank you.


回答1:


I fixed this issue by adding the canDeactivate inside my page.module.ts instead of app.module.ts




回答2:


It seems, canDeactivate not working on 'lazy loading'. Please check your route, and make sure, that you have set the component property.

Update with @rohan-sampat feedback.

It works. I too had issue with CanDeactivate in my project.

CanDeactivate-guard.service.ts

import { Observable } from 'rxjs';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

export interface CanComponentDeactivate {
  canComDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;  
}

export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {

  canDeactivate(component: CanComponentDeactivate,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return component.canComDeactivate();
  }

}

This is the component where I was using CanDeactivate to validate.

import { Component, EventEmitter, Output, OnInit } from "@angular/core";
import { DataService } from '../Shared/Service/DataService';
import { ActivatedRoute } from '@angular/router';
import { Subscription, Observable } from 'rxjs';
import { CanComponentDeactivate } from '../can-deactivate-guard.service';

@Component({
  selector: 'app-server',
  templateUrl: './server.component.html'
})

export class ServerComponent implements OnInit, CanComponentDeactivate {

  @Output() serverCreated = new EventEmitter<string>();

  queryParams: Subscription;
  data: string;

  canMove: false;

  userModel: any;
  constructor(private dataService: DataService, private route: ActivatedRoute) {

  }

  ngOnInit() {
    this.dataService.dataUpdate.subscribe(data => {
      this.data = data;
    })

    this.queryParams = this.route.queryParams.subscribe(data => {
      this.userModel = JSON.parse(data["model"]);
    })
  }


  canComDeactivate(): Observable<boolean> | Promise<boolean> | boolean {
    if (this.data == undefined || this.data == "") {
      var res = confirm("Text is blank");
      return res;
    }
    return this.canMove;
  }
}

The app.module.ts file in which I had my routes defined.

const appRoutes: Routes = [
 // { path: '', loadChildren: () => import('./Login/login.module').then(l => l.LoginModule) },
  { path: 'login', loadChildren: () => import('./Login/login.module').then(l => l.LoginModule) },
  { path: 'server', canActivate: [AuthGuard], canDeactivate: [CanDeactivateGuard], loadChildren: () => import('./severs/server.module').then(s => s.ServerModule) },
  { path: '**', component: ErrorComponent },
];

CanDeactivate on path Server was causing issue. If I was trying to go to another path outside the module, then id does not even hit the CanDeactivate guard.

But if I placed CanDeactivate from app.module to server.routes files, means in lazy loaded module itself to validate it, then it was working properly, as expected.

Server.route.ts file

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ServerComponent } from './server.component';
import { ErrorComponent } from './404.component';
import { CanDeactivateGuard } from '../can-deactivate-guard.service';

const route: Routes = [
  { path: '', component: ServerComponent },
  { path: 'server:/model', component: ServerComponent, canDeactivate: [CanDeactivateGuard] },
  { path: 'server', component: ServerComponent, canDeactivate: [CanDeactivateGuard] },

  { path: 'not-found', component: ServerComponent },
  //{ path: '**', component: ErrorComponent },

]

@NgModule({
  imports: [RouterModule.forChild(route)],
  exports: [RouterModule]
})

export class ServerRoute { }

Now after this change in solution, my code works was expected. Hope this helps.



来源:https://stackoverflow.com/questions/51450323/typeerror-cannot-read-property-candeactivate-of-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!