img - Guardias angulares, declaración poco clara en los documentos.
ng-src angular 5 (2)
Cuando piensas en enrutar, cuanto más profundo vayas al árbol, más específico te vuelves.
Por ejemplo:
/food-types/sweets/pies/blueberry
Entonces, cuando le dices a Angular que quieres CanDeactivate
del CanDeactivate
de arándanos, primero verifica CanDeactivate
en blueberry, porque estás retrocediendo por el árbol de navegación, a una ubicación diferente. CanActivateChild
también caminará por el árbol hacia el camino del niño, según mi entendimiento, por la misma razón: primero quiere verificar los niveles más profundos, para verificar que sus hijos puedan activarse.
Lo contrario es cierto de CanActivate
. Cuando le dices a Angular que quieres ver el pastel de blueberry
, estás caminando por el árbol y, por lo tanto, verifica la guardia en orden a medida que baja por el árbol.
Estoy tratando de entender profundamente el ángulo, así que leí los documentos y fue muy útil.
Ahora estoy estudiando a los guardias. Y leí esta declaración en los documentos.
El enrutador verifica primero los guardias CanDeactivate y CanActivateChild, desde la ruta secundaria más profunda hasta la cima. Luego verifica los guardias CanActivate de arriba hacia abajo hasta la ruta secundaria más profunda.
ahora estoy confundido, ¿por qué angular lo realiza de esta manera?
¿Hay algún beneficio de hacer la comprobación desde el niño más profundo hasta la cima para CanDeactivate & CanActivateChild ? y de arriba a la ruta infantil más profunda para CanActivate ?
Intenté creer lo que escribí en el sitio de documentos. Sin embargo, parece que no es del todo correcto, o la implementación se ha actualizado pero docs no se actualiza.
Ser breve:
Primero, CanDeactivate
guardas de CanDeactivate
se verifican de lo más profundo a lo más alto y CanActivate
guardias de CanActivate
se CanActivate
de arriba a lo más profundo (se cerrará con la verificación falsa en el recorrido).
En segundo lugar, los guardias de CanActivateChild
no se verifican desde lo más profundo hasta lo más alto .
TL; DR
Explicación detallada
Debemos comprobar la fuente para ver cómo funciona.
Nota: la confirmación verificada es: https://github.com/angular/angular/tree/edb8375a5ff15d77709ccf1759efb14091fa86a4
paso 1 - ver cuando se llamó a CanActivateChild
Este es solo el lugar runCanActivateChild
se llamó a su llamador superior runCanActivateChild
.
En esa línea, podemos obtener algún indicio de que hace el mismo truco que CanActivate
, ya que se llama después a la llamada superior de runCanActivate
.
paso 2 - ver cómo funciona runCanActivateChild
runCanActivateChild
se llamó dentro de la iteración de canActivateChecks
, igual que cómo se llamó runCanActivate
. Aquí sabemos que CanActivate
(me refiero a la función) y CanActivateChild
comparten la misma fuente de datos: canActivateChecks
.
Paso 3: ¿Qué es canActivateChecks
y cómo se procesa?
Entonces, ¿qué es canActivateChecks
? Obviamente, podemos descubrir que es una matriz de instancias de clase CanActivate
. Pero, ¿cómo se asigna canActivateChecks
? Vaya a aquí L865 . Esta es la parte importante, así que los voy a pegar aquí.
private traverseChildRoutes(
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null,
contexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[]): void {
const prevChildren = nodeChildrenAsMap(currNode);
// Process the children of the future route
futureNode.children.forEach(c => {
this.traverseRoutes(c, prevChildren[c.value.outlet], contexts, futurePath.concat([c.value]));
delete prevChildren[c.value.outlet];
});
// Process any children left from the current route (not active for the future route)
forEach(
prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) =>
this.deactivateRouteAndItsChildren(v, contexts !.getContext(k)));
}
private traverseRoutes(
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>,
parentContexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[]): void {
const future = futureNode.value;
const curr = currNode ? currNode.value : null;
const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null;
// reusing the node
if (curr && future._routeConfig === curr._routeConfig) {
if (this.shouldRunGuardsAndResolvers(
curr, future, future._routeConfig !.runGuardsAndResolvers)) {
this.canActivateChecks.push(new CanActivate(futurePath));
const outlet = context !.outlet !;
this.canDeactivateChecks.push(new CanDeactivate(outlet.component, curr));
} else {
// we need to set the data
future.data = curr.data;
future._resolvedData = curr._resolvedData;
}
// If we have a component, we need to go through an outlet.
if (future.component) {
this.traverseChildRoutes(
futureNode, currNode, context ? context.children : null, futurePath);
// if we have a componentless route, we recurse but keep the same outlet map.
} else {
this.traverseChildRoutes(futureNode, currNode, parentContexts, futurePath);
}
} else {
// ##### comment by e-cloud #####
if (curr) {
this.deactivateRouteAndItsChildren(currNode, context);
}
this.canActivateChecks.push(new CanActivate(futurePath));
// If we have a component, we need to go through an outlet.
if (future.component) {
this.traverseChildRoutes(futureNode, null, context ? context.children : null, futurePath);
// if we have a componentless route, we recurse but keep the same outlet map.
} else {
this.traverseChildRoutes(futureNode, null, parentContexts, futurePath);
}
}
}
Es un poco largo Pero si lo atraviesas, descubrirás que juega una profundidad de primer recorrido . Vamos a ignorar el mismo cambio de ruta. Busque el ##### comment by e-cloud #####
y vea el procedimiento principal. Muestra que primero actualiza canActivateChecks
luego realiza el siguiente nivel de travesía (Pre-order transversal en su totalidad).
Debe saber que el enrutador trata todas las rutas de la aplicación como un árbol de url. Cada PreActivation
divide su future
(como una ruta de árbol) en segmentos de ruta por el recorrido.
Tomemos un ejemplo simplificado :
Tenemos la ruta futura como
/a/b/c
.
Luego obtendremos [''/ a'', ''/ a / b'', ''/ a / b / c''] comocanActivateChecks
Aparentemente, canActivateChecks
representa las rutas de la parte superior a la más profunda del future
La fuente muestra que canActivateChecks
se itera de izquierda a derecha.
paso 4 - conclusión
podemos concluir que CanActivateChild
se ejecuta desde la parte superior hasta el niño más profundo.
Espero que lo explique claramente.