Router: CanDeactivate guards do not fire for componentless routes #12375

Closed
tdsmithATabc opened this Issue Oct 18, 2016 · 0 comments

Comments

Projects
None yet
3 participants
@tdsmithATabc

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior
Component-less routes (specifically in cases where the TreeNode is not reused) do not trigger CanDeactivate guards, but they always trigger CanActivate and CanActivateChild.

The underlying cause seems to be the behavior of Preactivation#traverseRoutes. In this conditional (router#L753), the deactivation for componentless routes is handled by calling deactivateOutletMap. However AFAICT, the parent outlet map is going to map each outlet directly to the component that contains it, effectively skipping any intermediary routes without components and never calling a cleanup/deactivation on them.

Expected behavior
I'm not completely certain if the intent is that guards apply to just components or to all routes. In any case, the activate/deactivate behavior should probably be symmetric. So either:

  1. All routes call CanDeactivate when they are navigated away from, OR
  2. Only component-having routes check guards.

I'm highly partial to the first option, but I could understand either argument. As I noted in another issue, the current routing documentation sounds like it is implying the first option:

We can have multiple guards at every level of a routing hierarchy. The router checks the CanDeactivate and CanActivateChild guards first, from deepest child route to the top. Then it checks the CanActivate guards from the top down to the deepest child route.

Minimal reproduction of the problem with instructions
A demonstration is available at http://plnkr.co/edit/WBO3kN?p=preview.

The only difference between the two main routes is that the "component branch" has a defined component (merely a dumb shell for a <router-outlet>), while the other does not. When leaving the component branch, the display shows DEACTIVATE: branch, while leaving

What is the motivation / use case for changing the behavior?
Our application has different resources types that need to be loaded and unloaded on the server side. These resources are mapped directly to the routing hierarchy (since they have a strict & universal ordering), so it's natural to put their release logic in deactivation guards. However most levels don't need components, so it's silly to have to create empty shell components everywhere just to support the deactivation.

Please tell us about your environment:
Mac OSX, Atom, npm, webpack, served via webpack-dev-server (dev) & nginx (prod).

  • Angular version: 2.0.X, 2.1.X (plunker demonstrates 2.1.0)
  • Browser: Only tested in Chrome 53, but should be relevant to all
  • Language: TypeScript, but should be relevant to all
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment