Je n'ai pas trouvé de solution standard, et celles proposées sur Internet sont limitées à une page. Par conséquent, j'ai écrit le mien et j'ai décidé de le partager.
Description du cas
Les pages d'application sont divisées en 3 groupes:
- Pour les utilisateurs autorisés uniquement
- Pour les utilisateurs non autorisés uniquement
- Pour tous les utilisateurs
Vous pouvez vous connecter ou vous déconnecter sur n'importe quelle page.
Si vous entrez / sortez sur une page à accÚs limité, vous devez accéder à la page autorisée.
Si la page n'a pas de restrictions, vous devez rester sur la page actuelle.
Pour une meilleure compréhension, il est conseillé de connaßtre:
DĂ©cision
La différenciation des droits d'accÚs aux pages s'effectue via guard - CanActivate. Le contrÎle est effectué lorsque vous accédez à la page, mais ne réagit pas aux changements de droits lorsque la transition a déjà été effectuée. Pour éviter la duplication de la logique des droits d'accÚs, nous redémarrons de force les gardes.
Le redémarrage des gardes pour la page actuelle se fait en naviguant dans l'url actuelle. Et les modifications apportées aux stratégies Router.onSameUrlNavigation et Route.runGuardsAndResolvers.
Voici une solution toute faite. Plus de détails dans la section suivante.
import { Injectable } from '@angular/core';
import { ActivatedRoute, PRIMARY_OUTLET, Router, RunGuardsAndResolvers } from '@angular/router';
@Injectable()
export class GuardControlService {
constructor(
private route: ActivatedRoute,
private router: Router,
) {}
/**
* guard- url
*/
forceRunCurrentGuards(): void {
// Router.onSameUrlNavigation url
const restoreSameUrl = this.changeSameUrlStrategy(this.router, 'reload');
// ActivatedRoute primary outlet
const primaryRoute: ActivatedRoute = this.getLastRouteForOutlet(this.route.root, PRIMARY_OUTLET);
// runGuardsAndResolvers ActivatedRoute url
const restoreRunGuards = this.changeRunGuardStrategies(primaryRoute, 'always');
//
this.router.navigateByUrl(
this.router.url
).then(() => {
// onSameUrlNavigation
restoreSameUrl();
// runGuardsAndResolvers
restoreRunGuards();
});
}
/**
* onSameUrlNavigation
* @param router - Router,
* @param strategy -
* @return callback
*/
private changeSameUrlStrategy(router: Router, strategy: 'reload' | 'ignore'): () => void {
const onSameUrlNavigation = router.onSameUrlNavigation;
router.onSameUrlNavigation = strategy;
return () => {
router.onSameUrlNavigation = onSameUrlNavigation;
}
}
/**
* route outlet-
* @param route - Route
* @param outlet - outlet-,
* @return ActivatedRoute outlet
*/
private getLastRouteForOutlet(route: ActivatedRoute, outlet: string): ActivatedRoute {
if (route.children?.length) {
return this.getLastRouteForOutlet(
route.children.find(item => item.outlet === outlet),
outlet
);
} else {
return route;
}
}
/**
* runGuardsAndResolvers ActivatedRoute ,
* @param route - ActivatedRoute
* @param strategy -
* @return callback
*/
private changeRunGuardStrategies(route: ActivatedRoute, strategy: RunGuardsAndResolvers): () => void {
const routeConfigs = route.pathFromRoot
.map(item => {
if (item.routeConfig) {
const runGuardsAndResolvers = item.routeConfig.runGuardsAndResolvers;
item.routeConfig.runGuardsAndResolvers = strategy;
return runGuardsAndResolvers;
} else {
return null;
}
});
return () => {
route.pathFromRoot
.forEach((item, index) => {
if (item.routeConfig) {
item.routeConfig.runGuardsAndResolvers = routeConfigs[index];
}
});
}
}
}
Description supplémentaire de la solution
La premiÚre chose que vous voulez essayer pour redémarrer les gardes est d'utiliser la navigation vers l'url actuelle.
this.router.navigateByUrl(this.router.url);
Mais, par défaut, l'événement de transition d'url actuel est ignoré et rien ne se passe. Pour que cela fonctionne, vous devez configurer le routage.
Configurer le routage
1. Changez la stratégie du routeur. onSameUrlNavigation
onSameUrlNavigation peut prendre les valeurs suivantes:
onSameUrlNavigation: 'reload' | 'ignore';
Pour la sensibilité à la transition vers l'url actuelle, vous devez définir «recharger».
Le changement de stratĂ©gie ne se recharge pas, mais gĂ©nĂšre un Ă©vĂ©nement de navigation supplĂ©mentaire. Il peut ĂȘtre obtenu via un abonnement:
this.router.events.subscribe();
2. Changez la stratégie d'itinéraire. runGuardsAndResolvers
runGuardsAndResolvers peut prendre les valeurs suivantes:
type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
Pour la sensibilité à la transition vers l'URL actuelle, vous devez définir «toujours».
Configuration du routage pendant la configuration de l'application
onSameUrlNavigation:
const routes: : Route[] = [];
@NgModule({
imports: [
RouterModule.forRoot(
routes,
{ onSameUrlNavigation: 'reload' }
)
]
})
runGuardsAndResolvers:
const routes: Route[] = [
{
path: '',
component: AppComponent,
runGuardsAndResolvers: 'always',
}
];
Configuration du routage au moment de l'exécution
constructor(
private router: Router,
private route: ActivatedRoute
) {
this.router.onSameUrlNavigation = 'reload';
this.route.routeConfig.runGuardsAndResolvers = 'always';
}
Redémarrage des gardes
Pour redémarrer les gardes d'une page spécifique, il suffit de configurer le routage lors de la configuration.
Mais pour recharger les gardes de n'importe quelle page, changer runGuardsAndResolvers dans chaque Route entraßnera des vérifications inutiles. Et la nécessité de toujours se souvenir de ce paramÚtre - aux erreurs.
Ătant donnĂ© que notre cas suppose un redĂ©marrage pour n'importe quelle page sans restrictions dans la configuration de l'application, vous avez besoin de:
1. Remplacez onSameUrlNavigation et conservez la valeur actuelle
// Router.onSameUrlNavigation url
const restoreSameUrl = this.changeSameUrlStrategy(this.router, 'reload');
...
/**
* onSameUrlNavigation
* @param router - Router,
* @param strategy -
* @return callback
*/
private changeSameUrlStrategy(router: Router, strategy: 'reload' | 'ignore'): () => void {
const onSameUrlNavigation = router.onSameUrlNavigation;
router.onSameUrlNavigation = strategy;
return () => {
router.onSameUrlNavigation = onSameUrlNavigation;
}
}
2. Obtenez ActivatedRoute pour l'url actuelle
Ătant donnĂ© que l'injection ActivatedRoute est effectuĂ©e dans le service, l'ActivatedRoute rĂ©sultant n'est pas associĂ© Ă l'url actuelle.
ActivatedRoute pour l'URL actuelle se trouve dans la derniĂšre prise principale et vous devez la trouver:
// ActivatedRoute primary outlet
const primaryRoute: ActivatedRoute = this.getLastRouteForOutlet(this.route.root, PRIMARY_OUTLET);
...
/**
* route outlet-
* @param route - Route
* @param outlet - outlet-,
* @return ActivatedRoute outlet
*/
private getLastRouteForOutlet(route: ActivatedRoute, outlet: string): ActivatedRoute {
if (route.children?.length) {
return this.getLastRouteForOutlet(
route.children.find(item => item.outlet === outlet),
outlet
);
} else {
return route;
}
}
3. Remplacez runGuardsAndResolvers pour tous les ActivatedRoute et ses ancĂȘtres, en conservant les valeurs actuelles
Un garde limitant l'accĂšs peut ĂȘtre situĂ© dans l'un des ancĂȘtres de l'actuel ActivatedRoute. Tous les ancĂȘtres sont situĂ©s dans pathFromRoot.
// runGuardsAndResolvers ActivatedRoute url
const restoreRunGuards = this.changeRunGuardStrategies(primaryRoute, 'always');
...
/**
* runGuardsAndResolvers ActivatedRoute ,
* @param route - ActivatedRoute
* @param strategy -
* @return callback
*/
private changeRunGuardStrategies(route: ActivatedRoute, strategy: RunGuardsAndResolvers): () => void {
const routeConfigs = route.pathFromRoot
.map(item => {
if (item.routeConfig) {
const runGuardsAndResolvers = item.routeConfig.runGuardsAndResolvers;
item.routeConfig.runGuardsAndResolvers = strategy;
return runGuardsAndResolvers;
} else {
return null;
}
});
return () => {
route.pathFromRoot
.forEach((item, index) => {
if (item.routeConfig) {
item.routeConfig.runGuardsAndResolvers = routeConfigs[index];
}
});
}
}
4. Accédez à l'url actuelle
this.router.navigateByUrl(this.router.url);
5. Remettez runGuardsAndResolvers et onSameUrlNavigation Ă leur Ă©tat d'origine
restoreRunGuards();
restoreSameUrl();
6. Combinez les Ă©tapes en une seule fonction
constructor(
private route: ActivatedRoute,
private router: Router,
) {}
/**
* guard- url
*/
forceRunCurrentGuards(): void {
// Router.onSameUrlNavigation url
const restoreSameUrl = this.changeSameUrlStrategy(this.router, 'reload');
// ActivatedRoute primary outlet
const primaryRoute: ActivatedRoute = this.getLastRouteForOutlet(this.route.root, PRIMARY_OUTLET);
// runGuardsAndResolvers ActivatedRoute url
const restoreRunGuards = this.changeRunGuardStrategies(primaryRoute, 'always');
//
this.router.navigateByUrl(
this.router.url
).then(() => {
// onSameUrlNavigation
restoreSameUrl();
// runGuardsAndResolvers
restoreRunGuards();
});
}
J'espÚre que cet article vous a été utile. S'il y a d'autres solutions, je serai heureux de les voir dans les commentaires.