1

I have a canDeactivate guard that checks if the route(Component) can be Deactivate. It works fine when I apply it on route.

const routes: Routes = [
  { path: '', component: MyComponent, canDeactivate: [MyGuard] }
]

I want this canDeactivate guard to be applied on all routes in my app, whether they are Lazy loaded/Pre Loaded/Loaded with app.

Note: I don't want to write this guard on all of my routes.

Is there any Observable, EvenEmitter or something that I could subscribe and update route by traversing to all routes?

Also, any traversing code that traverse through all Routes will be helpful.

Note: CanDeactivate does not get called when child route changes.

Thanks!

Irshad Ali
  • 1,153
  • 1
  • 13
  • 39

3 Answers3

1
  {
    path: '',
    component: LayoutBasicComponent,
    canActivate: [AuthGuard],
    canDeactivate: [CanLeaveProvide],
    runGuardsAndResolvers: 'paramsOrQueryParamsChange',
    children: [
      { path: '/path1', component: MyComponent1 }
    ]
  },
Sylvan LE DEUNFF
  • 682
  • 1
  • 6
  • 21
ivan
  • 11
  • 1
0

Something like this could do the job:

const routes: Routes = [
  { path: '', canDeactivate: [MyGuard], children: [
    { path: 'cmp1', component: MyComponent1 },
    { path: 'cmp2', component: MyComponent2 },
    { path: 'lazy', loadChildren: './modules/lazy/lazy.module#LazyModule' },
  ] },
];

Just add one root route with that guard and all other routes as its children.

Martin Adámek
  • 16,771
  • 5
  • 45
  • 64
  • 1
    What about lazy loaded modules? You can also attach to the Router events and implement deactivate logic in any custom handler function. But then you do not have guards layer but some not nice looking code – Karol Trybulec Sep 14 '18 at 09:29
  • 1
    not sure where you see difference for lazy routes, added one to my example, not tested but i do use similar approach in my app without any problems – Martin Adámek Sep 14 '18 at 09:32
  • @MartinAdámek It will not work canDeactivate guard do not run when child route changes – Irshad Ali Sep 14 '18 at 09:34
  • @KarolTrybulec Yes, you are right. I am also thinking of that. For now, I would prefer to wait for other great idea. – Irshad Ali Sep 14 '18 at 09:41
0

I have found an alternative to add a guard dynamically to any route from any component or sub-component (which is pretty useful).

For example, you can create your own guard which will prevent you from an unexpected window closing following this link.

Taking this example into account, let's say that the guard is named : "DownloadCenterGuard". Its purpose is to prevent your browser from closing if a download is currently running.

But as an Angular developer, the actual problem is that your DownloadCenterComponent is a deep sub-component which has no knowledge of which main component it is contained in (and you don't want to add the guard manually into all of your routes).

So the real question is : How the hell we can do that in Angular? (It works pretty well with Angular 12 and below, to confirm with future versions)

From your sub-component (anywhere into your app), inject the ActivatedRoute into the constructor:

@Component(...)
export class DownloadCenterComponent implements OnDestroy {

    constructor(
        private _activatedRoute: ActivatedRoute
    ) {
        // You could do the same for the "canActivate" property.
        this._activatedRoute.routeConfig.canDeactivate = [
            ...this._activatedRoute.routeConfig.canDeactivate,
            DownloadCenterGuard
        ];
    }
    
    ngOnDestroy() {
        // Remove the dynamically added guard at component destroying.
        this._activatedRoute.routeConfig.canDeactivate = [
            ...this._activatedRoute.routeConfig.canDeactivate.filter(guard => guard !== DownloadCenterGuard)
        ]
    }

}

And tadaaam, this is not documented anywhere and it could be unsupported by the Angular team at any time. So use this as less as possible, only if you have no other choice (in my opinion).

Antoine Rucquoy
  • 128
  • 1
  • 10