Как перейти к родительскому маршруту из дочернего маршрута?

89

Моя проблема вполне классическая. У меня есть личная часть приложения, которая находится за файлом login form. При успешном входе в систему он переходит на дочерний маршрут для приложения администратора.

Моя проблема в том, что я не могу использовать, global navigation menuпотому что маршрутизатор пытается маршрутизировать в моем, AdminComponentа не в моем AppCompoment. Так что у меня сломана навигация.

Другая проблема заключается в том, что если кто-то хочет получить доступ к URL напрямую, я хочу перенаправить на родительский маршрут «входа в систему». Но я не могу заставить его работать. Мне кажется, что эти две проблемы похожи.

Есть идеи, как это можно сделать?

Карл Бойсверт
источник
3
пожалуйста, добавьте код
Jiang YD

Ответы:

153

Вам нужна ссылка / HTML или вы хотите выполнить императивную маршрутизацию / в коде?

Ссылка : директива RouterLink всегда рассматривает предоставленную ссылку как дельту к текущему URL-адресу:

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

С RouterLink не забудьте импортировать и использовать directivesмассив:

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

Императив : navigate()метод требует отправной точки (то есть, relativeToпараметр). Если ничего не указано, навигация будет абсолютной:

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});
Марк Райкок
источник
1
этот router.navigate(string)метод, похоже, не существует в текущей версии Angular (2.2). Искал в документации и только нашел navigate(commands: any[], extras?: NavigationExtras) : Promise<boolean>. Или мне что-то совсем не хватает?
Tomato
2
@Tomato, вам нужно поставить [] вокруг маршрутов. Например, this.router.navigate (["../../ parent"], {relativeTo: this.route});
Ге
2
как передать relativeToданные, когда вы используете [routerLink] в HTML вместо машинописного текста?
redfox05
то же самое с услугами?
oCcSking
По какой-то причине в моем случае я должен использовать ../../../вместо ../перехода к родительскому ( '/users'от '/users/1').
nelson6e65
47

Кажется, это работает для меня весной 2017 года:

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

Если ваш компонент ctor принимает ActivatedRouteи Routerимпортируется следующим образом:

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

ne1410s
источник
4
Вместо даты было бы полезнее упомянуть версию Angular, которую вы используете.
isherwood
@isherwood Я согласен. Извинения. Если я правильно помню, я написал его для Angular 4.0.x, и он все еще работал в 4.3.x. К сожалению, сейчас я отошел от Angular,
ne1410s
@ ne1410s Большое спасибо, пропал родственник: this.route
Ян Самз
Примечание: НЕ будет работать с дополнительными сегментами маршрутизатора на модулях с отложенной загрузкой. EX:: parentPath'work: queue' (у которого есть дочерние элементы) и сказал, что дети загружают дочерний модуль с параметрами. fullCurrentPath: 'работа / доставка / модуль / список'. Приведенный выше код не может загружаться parentPathиз fullCurrentPath.
Дон Томас Бойл
32

Вы можете перейти к родительскому корню следующим образом

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

Вам нужно будет ввести текущий активный маршрут в конструктор

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

  }
Крис Ламот
источник
2
Добавление некоторых пояснений сделало бы этот ответ более полезным.
Сагар Зала
Многие предлагают перейти к брату с помощью this.router.navigate (["../ sibling"], {relativeTo: this.route}); Однако это больше не работает. Я нашел, что этот ответ, вероятно, работает. Вместо использования "../" для перехода к родительскому элементу. изменить relativeTo с this.route на this.route.parent - правильный путь
Терри Лам
1
@ChrisLamothe: О да, я совершил ошибку. Работает в общем случае. Однако на вспомогательных маршрутах он не работает. Это означает, что this.router.navigate (['../ sibling']) работает, но не this.router.navigate ([{outlets: {'secondary': ['../sibling']}}]). Во вспомогательной маршрутизации я должен использовать this.router.navigate ([{outlets: {'secondary': ['sibling']}}], {relativeTo: this.activatedRoute.parent}).
Терри Лэм
2
Кроме того, метод навигации из этого ответа this.router.navigate(['.'], {relativeTo: this.activeRoute.parent});будет работать правильно в случае, когда вы используете один и тот же компонент в двух путях: / users / create и / users / edit / 123. В обоих случаях он перейдет к родительскому элементу / пользователям. Обычная навигация с this.router.navigate([".."], {relativeTo: this.activeRoute})будет работать только для пользователей / create, но не будет работать для пользователей / edit / 123, потому что она перейдет к несуществующим / users / edit / route.
Роганик
1
+1 в качестве альтернативы, но лично я немного сторонник байтов и добавил бы дополнительную точку в параметр [".."] , чтобы исключить ссылку на родительский объект {relativeTo: this.route} .
Конрад Вильтерстен
7
constructor(private router: Router) {}

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

Маршрутизатор поддерживает

  • абсолютные пути /xxx- запускаются на маршрутизаторе корневого компонента
  • относительные пути xxx- запущены на маршрутизаторе текущего компонента
  • относительные пути ../xxx- запущены на родительском маршрутизаторе текущего компонента
Гюнтер Цёхбауэр
источник
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как он отвечает на вопрос, значительно улучшит его долгосрочную ценность. Пожалуйста, отредактируйте свой ответ, чтобы добавить пояснение.
Тоби Спейт
1
@TobySpeight Достаточно честно. Я предположил, что ../это достаточно хорошо известно, но в итоге все еще неоднозначно. Спасибо за подсказку.
Günter Zöchbauer
1
Спасибо за ответ, я работаю над этим сайтом довольно давно, так что с тех пор Angular, очевидно, обновился. Я пробовал это решение в своей текущей версии, но оно не работает. Позвольте мне обновить, и я прокомментирую позже.
Carl Boisvert
1
Я не могу заставить ваш код работать должным образом. Однако, если явно добавить {relativeTo: this.route} в качестве второго параметра в вызове для навигации , он работает. Я бы списал это на глупую опечатку, если бы не тот факт, что ваши ответы обычно имеют чрезвычайную точность. Возможно, это изменение в поведении маршрутизатора с тех пор, как был предоставлен ответ (3,6 года назад, что в Angular годы похоже на половинную вечность)?
Конрад Вильтерстен
Это старый ответ, и маршрутизатор за это время сильно изменился. Я думаю, что мой ответ просто устарел, учитывая, что есть несколько ответов с большим количеством голосов. Я больше не занимаюсь таким уж большим количеством вещей, связанных с веб-интерфейсом, и не знаю всех деталей в голове.
Günter Zöchbauer
6

Чтобы перейти к родительскому компоненту независимо от количества параметров в текущем маршруте или родительском маршруте: Обновление Angular 6 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);

Это дает дополнительный бонус в виде абсолютного маршрута, который вы можете использовать с одноэлементным маршрутизатором.

(Angular 4+ наверняка, возможно, Angular 2 тоже.)

Kayjtea
источник
как ни странно, при этом всегда возвращается пустой массив и достигается тот же результат, что this._router.navigate([])и при this._router.navigate([[]])переходе к родительскому маршруту тогда и только тогда, когда родительский маршрут сам не является корневым.
Ашиш Джанвар 08
обновлен код, чтобы отразить изменения Angular 6 и правильный поиск родителей с родительским и дочерним элементами, содержащими дочерние элементы в маршрутах.
Дон Томас Бойл
Вы уверены, что это не относится к вашему варианту использования? Казалось бы, не добавление последнего пути превратит ['orders', '123', 'items', 1] только в ['orders'], что вообще не кажется правильным. В любом случае, мы просто перешли с Angular 5 на 7 и не трогали этот код.
kayjtea
это количество div на моей странице .. щелчком каждого div я передаю параметры запроса и загружаю компонент. Теперь, используя кнопку "Назад" в браузере, я хочу вернуться, как это сделать?
Враджендра Сингх Мандлой,
4

Другой способ мог быть таким

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

а вот конструктор

constructor(
    private _activatedRoute: ActivatedRoute,
    private _router: Router
  ) { }
Johansrk
источник
3

без лишних слов:

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

параметр '..' делает навигацию на один уровень выше, т.е. родительский :)

Игорь Зинин
источник
Возможно, вы захотите упомянуть цель / необходимость skipLocationChange .
Конрад Вильтерстен
1

Мои маршруты имеют такую ​​схему:

  • пользователь / редактировать / 1 -> Изменить
  • пользователь / создать / 0 -> Создать
  • пользователь / -> Список

Например, когда я нахожусь на странице редактирования и мне нужно вернуться на страницу списка, я вернусь на 2 уровня вверх по маршруту.

Подумав об этом, я создал свой метод с параметром «уровень».

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

Итак, чтобы перейти от редактирования к списку, я вызываю такой метод:

this.goBack(2);
Carlinhos
источник
0

добавить Location в свой конструктор из @angular/common

constructor(private _location: Location) {}

добавить функцию возврата:

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

а затем, на ваш взгляд:

<button class="btn" (click)="back()">Back</button>
user3021615
источник
5
Это работает, только если вы ранее были на родительском маршруте. Родительские маршруты не имеют ничего общего с историей браузера ...
leviathanbadger
он перемещается назад, но не переходит к родительскому компоненту
Андрей Андреев
Это не следует использовать, если пользователь перейдет к компоненту с внешнего сайта, он будет возвращен на этот сайт. Этот код аналогичен нажатию
КНОПКИ
0

Если вы используете директиву uiSref, вы можете сделать это

uiSref="^"
Зуриэль
источник
0

Мое решение:

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

И Routerинъекция:

private readonly _router: Router
Anlijudavid
источник