I'm trying to understand angular deeply, so i read the docs and it was very helpful.
now i'm studying the guards. and i read this statement in the docs.
The router checks the CanDeactivate and CanActivateChild guards first, from the deepest child route to the top. Then it checks the CanActivate guards from the top down to the deepest child route.
now i'm confused, why does angular perform it in this way?
is there any benefits of doing the checking from the deepest child to the top for CanDeactivate & CanActivateChild. and from top to the deepest child route for CanActivate?
I had tried to believe what have written in the docs site. However, it appears it's not totally right, or the implementation has been updated but docs doesn't update.
To be Brief:
First,
CanDeactivate
guards are checked from deepest to top andCanActivate
guards are checked from top to deepest(it will quit with falsy check in the traversal).Second,
CanActivateChild
guards are not checked from deepest to top.TL;DR
Detail Explanation
we should check the source to see how it work.
step 1 - see when
CanActivateChild
got calledsource here L929.
This is only place its superior caller
runCanActivateChild
got called.At that line, we can get some hint that it does the same trick as
CanActivate
, becauseCanActivate
's superior callerrunCanActivate
is called after.step 2 - see how does
runCanActivateChild
workL926 and L950.
runCanActivateChild
got called within the iteration ofcanActivateChecks
, same as howrunCanActivate
got called. Here we knowCanActivate
(i mean the feature) andCanActivateChild
share the same data source --canActivateChecks
.step 3 - what is
canActivateChecks
and how does it get processedSo, what is
canActivateChecks
? Obviously, We can find out it's an array ofCanActivate
class instances. But how iscanActivateChecks
got assigned? Go to here L865. This is the important part, so i am going to paste them here.It's a little long. But If you go through it, you would figure out it plays a depth-first-traversal. Let's ignore the same route switching. Find
##### comment by e-cloud #####
and see the main procedure. It shows that it updates thecanActivateChecks
first then performs next level travesal(Pre-order traversal at whole).You must know the router treats all the routes of the app as a url tree. Each
PreActivation
split itsfuture
(as a tree path) into path segments by the traversal.Take a simplified example:
Apparently,
canActivateChecks
represents the routes from top to deepest of thefuture
The source showscanActivateChecks
is iterated from left to right.step 4 - conclusion
we can conclude that
CanActivateChild
is run from top to deepest child.Hope i explain it clearly.
When you think about routing, the deeper into the tree you go, the more specific you get.
For example:
/food-types/sweets/pies/blueberry
So when you tell Angular you want to navigate away from the
blueberry
pie, it checksCanDeactivate
on blueberry first, because you are walking back up the navigation tree, to a different location.CanActivateChild
will also walk up the tree to the child path, by my understanding, for the same reason: it wants to check the deepest levels first, to verify that their children can be activated.The converse is true of
CanActivate
. When you tell Angular you want to see theblueberry
pie, you are walking down the tree, and thus, it checks the guard in order as it walks down the tree.