Como faço para navegar para uma rota primária a partir de uma rota secundária?

94

Meu problema é bastante clássico. Eu tenho uma parte privada de um aplicativo que está por trás de um login form. Quando o login é bem-sucedido, ele segue para uma rota secundária do aplicativo admin.

Meu problema é que não consigo usar o global navigation menuporque o roteador tenta rotear no meu em AdminComponentvez do meu AppCompoment. Então minha navegação está quebrada.

Outro problema é que, se alguém deseja acessar a URL diretamente, desejo redirecionar para a rota de "login" pai. Mas não consigo fazer funcionar. Parece-me que essas duas questões são semelhantes.

Alguma ideia de como isso pode ser feito?

Carl Boisvert
fonte
3
por favor, adicione algum código
Jiang YD

Respostas:

157

Você quer um link / HTML ou deseja rotear imperativamente / no código?

Link : A diretiva RouterLink sempre trata o link fornecido como um delta para o URL atual:

[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"

Com o RouterLink, lembre-se de importar e usar a directivesmatriz:

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

Imperativo : o navigate()método requer um ponto de partida (ou seja, o relativeToparâmetro). Se nenhum for fornecido, a navegação é absoluta:

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
fonte
1
o router.navigate(string)método não parece existir na versão atual do Angular (2.2). Procurei na docs e apenas encontrei navigate(commands: any[], extras?: NavigationExtras) : Promise<boolean>. Ou estou totalmente perdendo alguma coisa?
Tomato
2
@Tomato, você precisa colocar [] em volta das rotas. Por exemplo, this.router.navigate (["../../ parent"], {relativeTo: this.route});
gye
2
como você passa os relativeTodados quando você está usando [routerLink] no html em vez de typescript?
redfox05
o mesmo com os serviços?
oCcSking
Por alguma razão, no meu caso tenho que usar em ../../../vez de ../para navegar até o pai ( '/users'de '/users/1').
nelson6e65 de
50

Isso parece funcionar para mim a partir da primavera de 2017:

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

Onde seu ctor de componente aceita ActivatedRoutee Router, importado da seguinte maneira:

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

ne1410s
fonte
4
Em vez de uma data, seria mais útil mencionar a versão Angular que você está usando.
isherwood
@isherwood eu concordo. Desculpas. Se bem me lembro, eu o escrevi para o Angular 4.0.xe ainda era funcional no 4.3.x. Infelizmente, eu me mudei do Angular agora,
ne1410s
@ ne1410s Muito obrigado estava faltando o parente: this.route
Ian Samz
Nota: NÃO funcionará com segmentos de roteador adicionais em módulos carregados lentamente. EX:: parentPath'work: queue' (que tem filhos) e esses filhos carregam o módulo filho com parâmetros. fullCurrentPath: 'trabalho / envio / módulo / lista'. O código acima não pode carregar parentPatha partir fullCurrentPath.
Don Thomas Boyle
34

Você pode navegar até sua raiz principal assim

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

Você precisará injetar a rota ativa atual no construtor

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

  }
Chris Lamothe
fonte
2
Adicionar alguma explicação tornaria essa resposta mais útil.
Sagar Zala
Muitas pessoas sugerem navegar até o irmão por this.router.navigate (["../ sibling"], {relativeTo: this.route}); No entanto, isso não está mais funcionando. Eu descobri que essa resposta provavelmente funcionou. Em vez de usar '../' para navegar até o pai. alterar relativeTo de this.route para this.route.parent é a maneira correta
Terry Lam
1
@ChrisLamothe: Sim, cometi um erro. Funciona no caso geral. No entanto, não funciona em rotas auxiliares. Isso significa que this.router.navigate (['../ sibling']) está funcionando, mas não this.router.navigate ([{outlets: {'secondary': ['../sibling']}}]). No roteamento auxiliar, preciso usar this.router.navigate ([{outlets: {'secondary': ['sibling']}}], {relativeTo: this.activatedRoute.parent}).
Terry Lam
2
Além disso, o método de navegação desta resposta this.router.navigate(['.'], {relativeTo: this.activeRoute.parent});funcionará corretamente em um caso, quando você usa o mesmo componente em dois caminhos: / users / create e / users / edit / 123. Em ambos os casos, ele navegará para pais / usuários. A navegação regular com this.router.navigate([".."], {relativeTo: this.activeRoute})funcionará apenas para os usuários / criar, mas não funcionará para os usuários / editar / 123 porque navegará para / usuários / editar / não existentes.
Roganik
1
1 para uma alternativa, mas pessoalmente, sou um pouco caçador de bytes e investiria um ponto extra no parâmetro, [".."] , para eliminar a referência ao pai, {relativeTo: this.route} .
Konrad Viltersten
7
constructor(private router: Router) {}

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

O roteador suporta

  • caminhos absolutos /xxx- iniciado no roteador do componente raiz
  • caminhos relativos xxx- iniciado no roteador do componente atual
  • caminhos relativos ../xxx- iniciados no roteador pai do componente atual
Günter Zöchbauer
fonte
Embora este código possa responder à pergunta, fornecer contexto adicional sobre por que e / ou como ele responde à pergunta melhoraria significativamente seu valor a longo prazo. Por favor edite sua resposta para adicionar alguma explicação.
Toby Speight
1
@TobySpeight Bastante justo. Presumi que ../fosse bem conhecido, mas no final ainda é ambíguo. Obrigado pela dica.
Günter Zöchbauer
1
Obrigado pela resposta, estou trabalhando neste site há algum tempo, então o Angular obviamente foi atualizado desde então. Eu tentei essa solução na minha versão atual e não funciona. Deixe-me atualizar e comentarei depois.
Carl Boisvert
1
Não consigo fazer seu código funcionar como esperado. No entanto, ao adicionar explicitamente , {relativeTo: this.route} como um segundo parâmetro na chamada para navegar , funciona. Eu atribuiria isso a um erro de digitação estúpido se não fosse pelo fato de que suas respostas geralmente têm um grau extremo de precisão. É talvez uma mudança no comportamento do roteador desde que a resposta foi fornecida (3,6 anos atrás, o que em anos angulares é como uma meia eternidade)?
Konrad Viltersten
Esta é uma resposta antiga e o roteador mudou muito neste momento. Acho que minha resposta está desatualizada, considerando que há várias respostas com mais votos positivos. Eu não estou mais fazendo muitas coisas de IU da web e não tenho todos os detalhes na minha cabeça.
Günter Zöchbauer
6

Para navegar até o componente pai , independentemente do número de parâmetros na rota atual ou na rota pai: Atualização do Angular 6 em 21/01/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);

Isso tem a vantagem adicional de ser uma rota absoluta que você pode usar com o roteador singleton.

(Angular 4+ com certeza, provavelmente Angular 2 também.)

Kayjtea
fonte
estranhamente, isso sempre retorna um array vazio, e obtém o mesmo resultado que this._router.navigate([]), enquanto this._router.navigate([[]])leva para a rota primária, se e somente se a rota primária não for o próprio root.
Ashish Jhanwar
código atualizado para refletir as alterações do Angular 6 e a localização adequada dos pais com pais e filhos contendo filhos nas rotas.
Don Thomas Boyle
Tem certeza de que não é algo específico para o seu caso de uso? Pareceria que não anexar o último caminho transformaria ['pedidos', '123', 'itens', 1] em apenas ['pedidos'], o que não parece certo. Em qualquer caso, apenas passamos do Angular 5 para o 7 e não tocamos neste código.
kayjtea
são o número de div na minha página .. ao clicar em cada div, passo parâmetros de consulta e carrego um componente. agora usando o botão voltar do navegador, eu quero voltar como fazer isso?
Vrajendra Singh Mandloi
4

Outra maneira poderia ser assim

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

e aqui está o construtor

constructor(
    private _activatedRoute: ActivatedRoute,
    private _router: Router
  ) { }
Johansrk
fonte
4

sem muito trabalho:

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

parâmetro '..' torna a navegação um nível acima, ou seja, pai :)

Igor Zinin
fonte
Você pode querer mencionar o propósito / necessidade de skipLocationChange .
Konrad Viltersten
1

Minhas rotas têm um padrão assim:

  • usuário / editar / 1 -> Editar
  • usuário / criar / 0 -> Criar
  • usuário / -> Lista

Quando estou na página de edição, por exemplo, e preciso voltar para a página da lista, irei retornar 2 níveis acima na rota.

Pensando nisso, criei meu método com um parâmetro "level".

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

Então, para ir da edição à lista, chamo o método assim:

this.goBack(2);
Carlinhos
fonte
0

Se você estiver usando a diretiva uiSref, você pode fazer isso

uiSref="^"
Zuriel
fonte
0

Minha solução é:

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

E a Routerinjeção:

private readonly _router: Router
anlijudavid
fonte
0

Nada disso funcionou para mim ... Eu tive que usar:

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

private router: Router

this.router.navigate([this.router.url.substring(0, this.router.url.lastIndexOf('/'))]);
Dimitri Dedusse Odyssound
fonte
Por favor, atualize sua resposta com alguma descrição de por que isso funciona. Por favor, veja como responder .
Gerald Zehetner
-2

adicione localização ao seu construtor de @angular/common

constructor(private _location: Location) {}

adicione a função back:

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

e então na sua visão:

<button class="btn" (click)="back()">Back</button>
user3021615
fonte
5
Isso só funciona se você estava na rota primária anteriormente. As rotas principais não têm nada a ver com o histórico do navegador ...
leviathanbadger
ele navega de volta, mas não navega para o pai do componente
Andrew Andreev
Isso não deve ser usado, se o usuário for para o componente de um site externo, ele será levado de volta para esse site. Este código é igual a clicar no botão VOLTAR NO NAVEGADOR
T04435