Comment naviguer vers un itinéraire parent à partir d'un itinéraire enfant?

89

Mon problème est assez classique. J'ai une partie privée d'une application qui se trouve derrière un fichier login form. Lorsque la connexion est réussie, elle est dirigée vers une route enfant pour l'application d'administration.

Mon problème est que je ne peux pas utiliser le global navigation menucar le routeur essaie de router dans mon AdminComponentau lieu de mon AppCompoment. Donc ma navigation est interrompue.

Un autre problème est que si quelqu'un veut accéder directement à l'URL, je veux rediriger vers la route de «connexion» parente. Mais je ne peux pas le faire fonctionner. Il me semble que ces deux problèmes sont similaires.

Une idée de la façon dont cela peut être fait?

Carl Boisvert
la source
3
veuillez ajouter du code
Jiang YD

Réponses:

153

Voulez-vous un lien / HTML ou voulez-vous router impérativement / en code?

Lien : la directive RouterLink traite toujours le lien fourni comme un delta de l'URL actuelle:

[routerLink]="['/absolute']"
[routerLink]="['../../parent']"
[routerLink]="['../sibling']"
[routerLink]="['./child']"     // or
[routerLink]="['child']" 

// with route param     ../../parent;abc=xyz
[routerLink]="['../../parent', {abc: 'xyz'}]"
// with query param and fragment   ../../parent?p1=value1&p2=v2#frag
[routerLink]="['../../parent']" [queryParams]="{p1: 'value', p2: 'v2'}" fragment="frag"

Avec RouterLink, n'oubliez pas d'importer et d'utiliser la directivesbaie:

import { ROUTER_DIRECTIVES } from '@angular/router';
@Component({
    directives: [ROUTER_DIRECTIVES],

Impératif : La navigate()méthode nécessite un point de départ (c'est-à-dire le relativeToparamètre). Si aucun n'est fourni, la navigation est absolue:

import { Router, ActivatedRoute } from '@angular/router';
...
constructor(private router: Router, private route: ActivatedRoute) {}
...
this.router.navigate(["/absolute/path"]);
this.router.navigate(["../../parent"], {relativeTo: this.route});
this.router.navigate(["../sibling"],   {relativeTo: this.route});
this.router.navigate(["./child"],      {relativeTo: this.route}); // or
this.router.navigate(["child"],        {relativeTo: this.route});

// with route param     ../../parent;abc=xyz
this.router.navigate(["../../parent", {abc: 'xyz'}], {relativeTo: this.route});
// with query param and fragment   ../../parent?p1=value1&p2=v2#frag
this.router.navigate(["../../parent"], {relativeTo: this.route, 
    queryParams: {p1: 'value', p2: 'v2'}, fragment: 'frag'});

// navigate without updating the URL 
this.router.navigate(["../../parent"], {relativeTo: this.route, skipLocationChange: true});
Mark Rajcok
la source
1
la router.navigate(string)méthode ne semble pas exister dans la version actuelle d'Angular (2.2). J'ai cherché dans les documents et je n'ai trouvé que navigate(commands: any[], extras?: NavigationExtras) : Promise<boolean>. Ou est-ce que je manque totalement quelque chose?
Tomate
2
@Tomato, vous devez mettre [] autour des routes. Par exemple, this.router.navigate (["../../ parent"], {relativeTo: this.route});
gye
2
comment passez-vous les relativeTodonnées lorsque vous utilisez [routerLink] dans le html au lieu de dactylographié?
redfox05
la même chose avec les services?
oCcSking le
Pour une raison quelconque, dans mon cas, je dois utiliser ../../../au lieu de ../pour naviguer vers le parent ( '/users'de '/users/1').
nelson6e65
47

Cela semble fonctionner pour moi au printemps 2017:

goBack(): void {
  this.router.navigate(['../'], { relativeTo: this.route });
}

Où votre composant ctor accepte ActivatedRouteet Router, importé comme suit:

import { ActivatedRoute, Router } from '@angular/router';

ne1410s
la source
4
Plutôt qu'une date, il serait plus utile de mentionner la version angulaire que vous utilisez.
isherwood
@isherwood Je suis d'accord. Toutes mes excuses. Si je me souviens bien, je l'ai écrit pour Angular 4.0.x et il était toujours fonctionnel en 4.3.x. Malheureusement, je me suis éloigné d'Angular maintenant,
ne1410s
@ ne1410s Merci beaucoup manquait le parent: this.route
Ian Samz
Remarque: ne fonctionnera PAS avec des segments de routeur supplémentaires sur des modules à chargement différé. EX:: parentPath'work: queue' (qui a des enfants) et lesdits enfants chargent le module enfant avec des paramètres. fullCurrentPath: 'travail / expédition / module / liste'. Le code ci-dessus ne peut pas charger à parentPathpartir de fullCurrentPath.
Don Thomas Boyle
32

Vous pouvez accéder à votre racine parent comme ceci

this.router.navigate(['.'], { relativeTo: this.activeRoute.parent });

Vous devrez injecter la Route active actuelle dans le constructeur

constructor(
    private router: Router,
    private activeRoute: ActivatedRoute) {

  }
Chris Lamothe
la source
2
L'ajout d'explications rendrait cette réponse plus utile.
Sagar Zala
Beaucoup de gens suggèrent de naviguer vers le frère par this.router.navigate (["../ sibling"], {relativeTo: this.route}); Cependant, cela ne fonctionne plus. J'ai trouvé que cette réponse fonctionnait probablement. Au lieu d'utiliser «../» pour accéder au parent. changer relativeTo de this.route à this.route.parent est le bon chemin
Terry Lam
1
@ChrisLamothe: Oh oui j'ai fait une erreur. Cela fonctionne dans le cas général. Cependant, cela ne fonctionne pas dans les routes auxiliaires. Cela signifie que this.router.navigate (['../ sibling']) fonctionne mais pas this.router.navigate ([{outlets: {'secondary': ['../sibling']}}]). Dans le routage auxiliaire, je dois utiliser this.router.navigate ([{outlets: {'secondary': ['sibling']}}], {relativeTo: this.activatedRoute.parent}).
Terry Lam
2
De plus, la méthode de navigation de cette réponse this.router.navigate(['.'], {relativeTo: this.activeRoute.parent});fonctionnera correctement dans un cas, lorsque vous utilisez le même composant dans deux chemins: / users / create et / users / edit / 123. Dans les deux cas, il accédera aux parents / utilisateurs. La navigation régulière avec this.router.navigate([".."], {relativeTo: this.activeRoute})ne fonctionnera que pour les utilisateurs / create, mais ne fonctionnera pas pour les utilisateurs / edit / 123 car elle naviguera vers non-existant / users / edit / route.
Roganik
1
+1 pour une alternative mais personnellement, je suis un peu un chasseur d'octets et j'investirais un point supplémentaire dans le paramètre, [".."] , pour éliminer la référence au parent, {relativeTo: this.route} .
Konrad Viltersten
7
constructor(private router: Router) {}

navigateOnParent() {
  this.router.navigate(['../some-path-on-parent']);
}

Le routeur prend en charge

  • chemins absolus /xxx- démarrés sur le routeur du composant racine
  • chemins relatifs xxx- démarrés sur le routeur du composant actuel
  • chemins relatifs ../xxx- démarrés sur le routeur parent du composant actuel
Günter Zöchbauer
la source
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire sur la raison et / ou la façon dont il répond à la question améliorerait considérablement sa valeur à long terme. Veuillez modifier votre réponse pour ajouter des explications.
Toby Speight
1
@TobySpeight Très bien. Je suppose que ../c'est assez bien connu, mais au final c'est toujours ambigu. Merci pour l'indice.
Günter Zöchbauer
1
Merci pour la réponse, je travaille sur ce site depuis un certain temps, donc Angular a évidemment été mis à jour depuis. J'ai essayé cette solution dans ma version actuelle et cela ne fonctionne pas. Permettez-moi de mettre à jour et je reviendrai après.
Carl Boisvert
1
Je ne fais pas fonctionner votre code comme prévu. Cependant, en ajoutant explicitement {relativeTo: this.route} comme second paramètre dans l'appel à naviguer , cela fonctionne. Je considérerais cela comme une faute de frappe stupide s'il n'y avait pas eu le fait que vos réponses ont généralement un degré extrême de précision. S'agit-il peut-être d'un changement de comportement du routeur depuis que la réponse a été apportée (il y a 3,6 ans, ce qui en années angulaires est comme une demi-éternité)?
Konrad Viltersten
C'est une vieille réponse et le routeur a beaucoup changé à ce moment. Je pense que ma réponse est juste obsolète étant donné qu'il y a plusieurs réponses avec plus de votes positifs. Je ne fais plus autant de trucs d'interface utilisateur Web et je n'ai pas tous les détails en tête.
Günter Zöchbauer
6

Pour naviguer vers le composant parent quel que soit le nombre de paramètres de l'itinéraire actuel ou de l'itinéraire parent: Mise à jour angulaire 6 1/21/19

   let routerLink = this._aRoute.parent.snapshot.pathFromRoot
        .map((s) => s.url)
        .reduce((a, e) => {
            //Do NOT add last path!
            if (a.length + e.length !== this._aRoute.parent.snapshot.pathFromRoot.length) {
                return a.concat(e);
            }
            return a;
        })
        .map((s) => s.path);
    this._router.navigate(routerLink);

Cela a l'avantage supplémentaire d'être une route absolue que vous pouvez utiliser avec le routeur singleton.

(Angular 4+ bien sûr, probablement Angular 2 aussi.)

kayjtea
la source
bizarrement, cela retourne toujours un tableau vide et obtient le même résultat que this._router.navigate([]), while this._router.navigate([[]])prend la route parente, si et seulement si la route parente n'est pas racine elle-même.
Ashish Jhanwar
code mis à jour pour refléter les changements Angular 6 et la recherche de parent appropriée avec le parent et l'enfant contenant des enfants dans les itinéraires
Don Thomas Boyle
Êtes-vous sûr que ce n'est pas quelque chose de spécifique à votre cas d'utilisation? Il semblerait que ne pas ajouter le dernier chemin transformerait ['commandes', '123', 'articles', 1] en seulement ['commandes'], ce qui ne semble pas du tout correct. Dans tous les cas, nous sommes juste passés de Angular 5 à 7 et n'avons pas touché à ce codé.
kayjtea
leur nombre de div sur ma page .. sur clic de chaque div je passe des paramètres de requête et charge un composant. maintenant en utilisant le bouton de retour du navigateur, je veux revenir en arrière
Vrajendra Singh Mandloi
4

Une autre façon pourrait être comme ça

this._router.navigateByUrl(this._router.url.substr(0, this._router.url.lastIndexOf('/'))); // go to parent URL

et voici le constructeur

constructor(
    private _activatedRoute: ActivatedRoute,
    private _router: Router
  ) { }
Johansrk
la source
3

sans trop tarder:

this.router.navigate(['..'], {relativeTo: this.activeRoute, skipLocationChange: true});

le paramètre '..' rend la navigation d'un niveau supérieur, c'est-à-dire parent :)

Igor Zinin
la source
Vous voudrez peut-être mentionner le but / la nécessité de skipLocationChange .
Konrad Viltersten
1

Mes itinéraires ont un modèle comme celui-ci:

  • utilisateur / modifier / 1 -> Modifier
  • user / create / 0 -> Créer
  • utilisateur / -> Liste

Lorsque je suis sur la page Modifier, par exemple, et que j'ai besoin de revenir à la page de liste, je reviendrai 2 niveaux plus haut sur l'itinéraire.

En y réfléchissant, j'ai créé ma méthode avec un paramètre "level".

goBack(level: number = 1) {
    let commands = '../';
    this.router.navigate([commands.repeat(level)], { relativeTo: this.route });
}

Donc, pour passer de l'édition à la liste, j'appelle la méthode comme ça:

this.goBack(2);
Carlinhos
la source
0

ajouter un emplacement à votre constructeur à partir de @angular/common

constructor(private _location: Location) {}

ajoutez la fonction de retour:

back() {
  this._location.back();
}

et ensuite à votre avis:

<button class="btn" (click)="back()">Back</button>
utilisateur3021615
la source
5
Cela ne fonctionne que si vous étiez auparavant dans l'itinéraire parent. Les itinéraires parents n'ont rien à voir avec l'historique du navigateur ...
leviathanbadger
il navigue en arrière, mais ne navigue pas vers le parent du composant
Andrew Andreev
Cela ne doit pas être utilisé, si l'utilisateur accède au composant à partir d'un site externe, il sera ramené sur ce site. Ce code
équivaut
0

Si vous utilisez la directive uiSref, vous pouvez le faire

uiSref="^"
Zuriel
la source
0

Ma solution est:

const urlSplit = this._router.url.split('/');
this._router.navigate([urlSplit.splice(0, urlSplit.length - 1).join('/')], { relativeTo: this._route.parent });

Et l' Routerinjection:

private readonly _router: Router
anlijudavid
la source