Работая над моей работой — вместе с учебником Angular «Tour of Heroes», я пытаюсь увидеть, как работают дочерние маршруты. У меня есть HeroesComponent со встроенным <router-outlet></router-outlet>
. HeroesComponent, доступ к которому осуществляется через «/heroes», отображает список ссылок для отдельных героев, для каждой из которых routerLink
установлено значение «/heroes/[id]», при этом идентификатор этого героя отображается вместо «[id]» — «/heroes/». 7', например.
(Я знаю, как добавить дочерний компонент непосредственно в родительский компонент без использования дочернего маршрута. Моя цель здесь — узнать, как работают дочерние маршруты. С прямым дочерним компонентом я знаю, как использовать ngOnChanges, но в этом случае это не так. меняется не свойство компонента @Input, а свойство маршрутизатора.)
Маршрутизация
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'heroes', component: HeroesComponent, runGuardsAndResolvers: 'always', children: [
{ path: ':id', component: HeroDetailComponent, runGuardsAndResolvers: 'always' }
] },
{ path: 'dashboard', component: DashboardComponent }
];
Выход дочернего маршрутизатора в родительском HeroesComponent
<section>
<h2>All Heroes</h2>
<div><a routerLink = "/detail">Create a hero</a></div>
<table class = "table">
<thead>
<tr><th>Name</th><th>Location</th></tr>
</thead>
<tbody>
<tr *ngFor = "let hero of heroes">
<th><a routerLink = "/heroes/{{hero.id}}">{{hero.name}}</a></th>
<td>{{hero.location}}</td>
<td><a (click) = "delete(hero.id)">delete</a></td>
</tr>
</tbody>
</table>
</section>
<router-outlet></router-outlet>
Код ключа в дочернем компоненте HeroDetailComponent
ngOnInit(): void {
let id: string;
// I'll explain this comment later.
// this.route.paramMap.subscribe((paramMap) => id = paramMap.get('id'));
id = this.route.snapshot.paramMap.get('id');
if (id) {
this.mode = 'update';
this.heroService.getHero(+id).subscribe((hero) => {
this.hero = hero
});
} else {
this.mode = 'add';
this.hero = { id: 0, name: '', location: '', cuisine: 0 }
}
}
Переход к /heroes дает мне следующее. (У меня уже был настроен API ресторана для руководства по .NET CORE, поэтому я использую его в качестве источника данных для этого руководства по Angular.)
Поле адреса браузера показывает «localhost:4200/heroes». Когда я навожу курсор на Masseria, в строке состояния браузера (это Chrome в Windows 10, если это имеет значение) отображается «http://localhost:4200/heroes/9». Перейдя по ссылке Masseria, я получаю:
Все идет нормально! Но затем, когда я нажимаю, скажем, на ссылку Takumi, хотя содержимое поля адреса браузера правильно изменяется на «http://localhost:4200/heroes/13», отображение не меняется: я все еще вижу детали для Masseria.
Теперь, если я щелкну адресное поле браузера и нажму Enter, вся страница обновится, показывая мне как список ресторанов, так и сведения о Такуми.
Я полагаю, что какое-то необходимое уведомление об обновлении не происходит. Я провел небольшое исследование. Что касается строки, которую я закомментировал в последнем фрагменте кода выше, я подумал, что, возможно, явная подписка на параметр маршрутизатора :id поможет, используя
this.route.paramMap.subscribe((paramMap) => id = paramMap.get('id'));
вместо того, чтобы брать параметр из моментального снимка маршрутизатора. Это не имело никакого эффекта.
Я также попытался добавить атрибут runGuardsAndResolvers: 'always'
к родительскому и дочернему путям в моем массиве маршрутов (первый фрагмент кода выше), но это также не дало никакого эффекта.
Акк, понял. Я был на полпути с подпиской в OnInit на paramMap роутера:
this.route.paramMap.subscribe((paramMap) => id = paramMap.get('id'));
Часть, которую я упустил, заключается в том, что все вычисления состояния должны быть внутри обратного вызова подписки, а не только установка значения идентификатора. Вот:
ngOnInit(): void {
let id: string;
this.route.paramMap.subscribe((paramMap) => {
id = paramMap.get('id');
if (id) {
this.mode = 'update';
this.heroService.getHero(+id).subscribe((hero) => {
this.hero = hero
});
} else {
this.mode = 'add';
this.hero = { id: 0, name: '', location: '', cuisine: 0 }
}
}
);
Теперь работает как задумано.