Angular2: CanDeactivate guard

I created a CanDeactivate protector that returns the observable and applies to the component that loads into the internal nested router output. Should this guard be called up whenever you try to jump to another URL? I ask about this because this does not happen in my case.

In my case, the guard will only be called for the first "other" URL. Let me try to explain this with an example. Suppose I always return false, and I'm trying to navigate to other URLs from the same component:

/A --> guard called /B --> guard called /B --> no navigation and no guard called /A --> guard called /A -->guard not called and no navigation 

Is this the expected behavior?

edit Well, that seems to be the case. Just built a small sample with three components, and the guard will be called only for the first time the user tries to go to a specific URL ... this is really strange ...

Anyway, here is the code I'm using:

 // app.routing import {NgModule} from "@angular/core"; import {Routes, RouterModule, Route, CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot} from "@angular/router"; import { MainComponent } from "./main/main.component"; import { OtherComponent } from "./other/other.component"; import { Other3Component } from "./other3/other3.component"; import {Observable} from "rxjs/observable"; const fallback: Route = { path: "**", redirectTo: "/main", pathMatch: "full" }; export class Test implements CanDeactivate<MainComponent>{ canDeactivate(component: MainComponent, route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean{ console.log("in"); return false; } } export const rotas: Routes = [ { path: "main", component: MainComponent, canDeactivate: [Test] }, { path: "other", component: OtherComponent }, { path: "other3", component: Other3Component }, fallback ]; @NgModule({ imports: [RouterModule.forRoot(rotas)], exports: [RouterModule] }) export class AppRoutingModule{} 

//app.component.html <h1> <a routerLink="/main">Main</a> <a routerLink="/other">Other</a> <a routerLink="/other3">Other3</a> </h1>

Everything was created via angular-cli (for example: ng component XXX). Yes, CanDeactivate protection always returns false, so you cannot unload the main component. So, the first time I press another, the guard receives a call. If you click on another again, no defender will be called. However, if I click on another 3, then the guard will be called. Clicking on another 3 will really do nothing until I click on another link (for example: different) ...

Is this the expected behavior? I have to say that I expected my guards to hit every time I click on another link ...

Thanks.

Louis

+5
source share
2 answers

Damn it, mistake ... Pay attention to yourself: next time check the problem panel first.

https://github.com/angular/angular/issues/12851#event-880719778

+2
source

I found this solution, instead of creating a candeactivate security element for each component, you will create one guard service and add the candeactivate method for each component that you want to add this parameter, so you must first add this service file "deactivate-guard.service .ts ":

 import { Injectable } from '@angular/core'; import { CanDeactivate } from '@angular/router'; import { Observable } from 'rxjs/Observable'; export interface CanComponentDeactivate { canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean; } @Injectable() export class DeactivateGuardService implements CanDeactivate<CanComponentDeactivate>{ canDeactivate(component: CanComponentDeactivate) { return component.canDeactivate ? component.canDeactivate() : true; } } 

then you must specify in the application module:

 providers: [ DeactivateGuardService ] 

now in the component you want to protect add the function:

 export class ExampleComponent { loading: boolean = false; //some behaviour that change the loading value canDeactivate() { console.log('i am navigating away'); if (this.loading) { console.log('no, you wont navigate anywhere'); return false; } console.log('you are going away, goodby'); return true; } } 

you can see that the load variable is local to the component. the last step is to add the directive to the routing module component:

 { path: 'example', canDeactivate: [DeactivateGuardService], component: ExampleComponent } 

And that, I hope it was useful, goodluck.

+9
source

Source: https://habr.com/ru/post/1261279/


All Articles