Angular 5: как мне направить все пути для выхода к одному и тому же компоненту, используя только 1 маршрут?

Моя текущая конфигурация:

const routes: Routes = [
  { path: '', component: NavComponent, outlet: 'nav' },  // (1)
  { path: '**', component: NavComponent, outlet: 'nav' } // (2)
];

Оно работает. NavComponent всегда выводится на выход nav. В частности, он работает для всех следующих типов URL-адресов:

http://example.com/foo(nav:bar)     // (a) non-empty path in nav   -->  (2)
http://example.com/foo(nav:)        // (b) empty path in nav       -->  (2)
http://example.com/foo              // (c) no nav at all           -->  (1)

Обратите внимание, что маршрутизатор сопоставляет разные маршруты с этими URL-адресами:

  • (1) используется для (c)
  • (2) используется для (a) и (b)

Вот почему экземпляр NavComponent уничтожается и создается заново каждый раз, когда меняется местоположение, скажем, с (c) на (a). И это то, что мне нужно предотвратить. Мне нужно сохранить мой экземпляр из-за его состояния, анимации и т. д. Насколько я понимаю, это возможно только в том случае, если для всех URL-адресов используется один и тот же маршрут, однако я не могу найти способ сделать это. Если я удалю (1), URL-адреса типа (c) перестанут показывать NavComponent в nav. По-видимому, ** не соответствует таким URL-адресам (хотя я не уверен, почему).

Вы можете увидеть это в действии здесь: https://stackblitz.com/edit/angular-ptzwrm

Какое правильное решение здесь?

На данный момент я переопределяю UrlSerializer, чтобы добавить (nav:) к URL-адресам, таким как (c), перед синтаксическим анализом, но это похоже на взлом.


person thorn0    schedule 12.02.2018    source источник
comment
Можете ли вы предоставить минимальный репо с вашим патчем? Посмотрим, можно ли сделать что-то более нехакерское   -  person Tarun Lalwani    schedule 15.02.2018
comment
Если вы используете один и тот же компонент снова и снова, почему вы используете routerLinks? Разве вы не можете просто остаться на NavComponent и обновить информацию?   -  person Scuba Kay    schedule 16.02.2018
comment
stackblitz.com/edit/angular-ptzwrm   -  person thorn0    schedule 16.02.2018
comment
@ScubaKay Потому что я хочу отразить состояние этого компонента в URL-адресе.   -  person thorn0    schedule 16.02.2018
comment
@thorn, похоже, веская причина   -  person Scuba Kay    schedule 16.02.2018
comment
@thorn Я думаю, вам вообще не нужен маршрутизатор. Удалите все вокруг Router (файл маршрута + routerLink) и используйте QueryParams.   -  person Gilsdav    schedule 19.02.2018
comment
@Gilsdav Я понимаю, почему ты это предлагаешь. Мое приложение сложнее, чем эта отдельная проблема. Выход обеспечивает большую гибкость, чем прослушивание параметров запроса. У него есть приятные черты, такие как охрана. И в этой розетке будут и другие компоненты. Я просто не мог понять, зачем мне два маршрута, хотя кажется, что одного будет достаточно. Первичная розетка так себя не ведет.   -  person thorn0    schedule 19.02.2018
comment
@thorn хорошо, если вы добавите что-то на свой путь, это то же самое? {путь: 'test', компонент: NavComponent, выход: 'nav' } example.com/ foo/test(nav;bar)   -  person Gilsdav    schedule 19.02.2018
comment
@Gilsdav Итак, я до сих пор не совсем понимаю эту вещь '**' против '', это может быть даже ошибка в Angular или, что более вероятно, просто одно из многих недокументированных небольших дизайнерских решений. Однако решение с RouteReuseStrategy кажется мне достаточно хорошим. По крайней мере, это работает, и компонент не перезагружается. Я соглашусь, хотя здесь для меня не все ясно.   -  person thorn0    schedule 19.02.2018
comment
@thorn '' — это когда у вас ничего нет после foo, а '**' — если у вас есть что-то (все остальное) после foo. Что у меня есть в голове, так это использование pathMatch: префикс на вашем пути ''. Не пробовал.   -  person Gilsdav    schedule 19.02.2018
comment
@Gilsdav Я пробовал. Я даже пытался использовать пользовательский matcher, но он просто не вызывается для URL-адресов типа (c).   -  person thorn0    schedule 19.02.2018
comment
Похоже, что для именованных розеток есть разница между значениями: пустая строка (b) и null (c). В то время как путь основного выхода просто не может быть null, так как эта часть URL-адреса не считается необязательной. Для корня сайта путь представляет собой пустую строку.   -  person thorn0    schedule 19.02.2018
comment
Хорошо, хорошо знать. Извините, я не смогу помочь. Я лично избегаю использования именованной розетки.   -  person Gilsdav    schedule 19.02.2018


Ответы (2)


Глупый вопрос, но не можете ли вы просто изменить URL-адрес с помощью службы определения местоположения и остаться на том же компоненте (и просто изменить состояния для своих анимаций)?

В противном случае вы можете реализовать собственную RouteReuseStrategy, чтобы принудительно повторно использовать ваш компонент.

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

import {ActivatedRouteSnapshot} from '@angular/router';
import { DetachedRouteHandle } from '@angular/router';


/** Use defaults from angular internals, apart from shouldReuseRoute **/


 export class CustomReuseStrategy implements RouteReuseStrategy {
    shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; }
    store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
    shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; }
    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; }


   shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
       let name = future.component && (<any>future.component).name;

    return future.routeConfig === curr.routeConfig || name == "NavComponent";
  }
}


@NgModule({

  providers: [

    {
      provide: RouteReuseStrategy,
      useClass: CustomReuseStrategy
    }]
})
export class AppModule { }

Вот ваш модифицированный stackblitz, который всегда будет повторно использовать ваш NavComponent.

https://stackblitz.com/edit/angular-tj5nrm?file=app/app.module.ts

Ссылки

Объяснение стратегии повторного использования маршрута: https://medium.com/@gerasimov.pk/how-to-reuse-rendered-component-in-angular-2-3-with-routereusestrategy-64628e1ca3eb

Значения по умолчанию для стратегии углового маршрутизатора: https://github.com/angular/angular/blob/master/packages/router/src/route_reuse_strategy.ts

person David    schedule 17.02.2018

Я имею в виду, что вам нужен вложенный маршрутизатор-розетка. Что-то вроде этого:

app.component.html: <router-outlet></router-outlet>

feature-area.component.html: <your-navbar-component></your-navbarcomponent> <router-outlet></router-outlet>

child-of-feature-area.component.html: < h1>Hi there!</h1>

your-navbar-component.component.html: < p>some links here...</p>

Когда вы получите доступ к http://localhost:4200/feature-path/child-feature-path, вы получите:

некоторые ссылки здесь...

Привет!

Если вам нужно, я могу написать какой-нибудь плакер с примером, чтобы лучше объяснить. Но я к тому, что вы перегружаете роутер задачей, которая, может быть, и не к нему.

person Christian G Fritsch    schedule 16.02.2018
comment
Извините, я не понимаю, насколько ваш ответ актуален. Взгляните на мой пример кода здесь, чтобы увидеть, чего я пытаюсь достичь: stackblitz.com/edit/ угловой-ptzwrm - person thorn0; 16.02.2018
comment
Я думаю, что вы хотите отразить в URL-адресе состояние панели навигации. Я могу использовать queryParams для достижения этой цели и вложенные маршрутизаторы для сохранения панели навигации, не уничтожая и не создавая ее каждый раз заново. - person Christian G Fritsch; 16.02.2018
comment
Итак, вы предлагаете вообще не использовать вторичные (именованные) розетки, верно? Но мне кажется, что они созданы именно для такого использования. - person thorn0; 16.02.2018
comment
Одним из примеров использования именованных выходов, где это работает довольно хорошо, являются модальные окна. Я не говорю не использовать вторичные маршруты - я просто думаю, что вы можете делать то, что хотите, используя другой подход, не перегружая ответственность маршрутизатора. Или ваш вопрос касается выбора лучших практик? - person Christian G Fritsch; 16.02.2018