Как проложить маршрут к модулю в качестве дочернего модуля - Angular 2 RC 5
В процессе обновления приложения я работаю с последним кандидатом на выпуск Angular 2. В рамках этой работы я пытаюсь использовать спецификацию NgModule и переносить все части своего приложения на модули. По большей части это прошло очень хорошо, за исключением проблемы с маршрутизацией.
"@angular/common": "2.0.0-rc.5",
"@angular/compiler": "2.0.0-rc.5",
"@angular/core": "2.0.0-rc.5",
"@angular/forms": "0.3.0",
"@angular/http": "2.0.0-rc.5",
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"@angular/router": "3.0.0-rc.1",
Мое приложение построено как состав модулей, при этом несколько модулей склеиваются как дочерние элементы родительского модуля. Например, у меня есть модуль администратора, который состоит из модуля уведомлений, модуля пользователей и телефонного модуля (например). Маршруты к этим модулям должны выглядеть как...
/admin/notifications/my-notifications
/admin/users/new-user
/admin/telephony/whatever
В более ранней версии маршрутизатора это было легко выполнить с помощью "children"
export const AdminRoutes: RouterConfig = [
{
path: "Admin",
component: AdminComponent,
Children: [
...UserRoutes,
...TelephonyRoutes,
...NotificationRoutes
]
}
]
В другом файле, как части подмодулей, я бы определил маршруты отдельных модулей, а также i.e.
export const UserRoutes: RouterConfig = [
{
path: "users",
component: userComponent,
children: [
{path: "new-user", component: newUserComponent}
]
}
]
Все это работало очень хорошо. В процессе обновления до модулей я переместил все в свои собственные файлы маршрутизации, а теперь эти два больше похожи на это.
const AdminRoutes: Routes = [
{path: "admin", component: AdminComponent}
]
export const adminRouting = RouterModule.forChild(AdminRoutes)
и
const UserRoutes: Routes = [
path: "users",
component: userComponent,
children: [
{path: "new-user", component: newUserComponent}
]
]
export const userRouting = RouterModule.forChild(UserRoutes)
Со всем этим на месте у меня есть UserModule, который импортирует userRouting, а затем AdminModule, который импортирует adminRoutes и UserModule. Я думал, что поскольку UserModule является дочерним элементом AdminModule, маршрутизация будет работать так, как она привыкла. К сожалению, это не так, я в конечном итоге с маршрутом пользователей, который просто
/users/new-user
вместо
/admin/users/new-user
Кроме того, из-за этого компонент нового пользователя не загружается в розетку маршрутизатора моего админ-компонента, который отменяет стиль и навигацию моего приложения.
Я не могу на всю жизнь придумать, как ссылаться на маршруты моего UserModule в качестве дочерних элементов моего AdminModule. Я попытался сделать это по-старому и получить ошибки о маршрутах, находящихся в двух модулях. Очевидно, так как это недавно выпущено, документация по некоторым из этих случаев немного ограничена.
Любая помощь, которую любой может предоставить, будет с благодарностью!
Ответы
Ответ 1
Хорошо, после того, как я занялся этим в течение большей части уик-энда, у меня это закончилось. Для меня в конце концов было сделано следующее:
- Экспортировать все
Routes
для каждого модуля, который вы хотите маршрутизировать. Не импортируйте ни одного из RouterModule.forChild()
в дочерние модули.
- Экспортировать каждый компонент, видимый из определений маршрута childs в определении модуля childs.
- Импорт (что означает Typescript
import
) все дочерние маршруты, как обычно, и используйте оператор ...
, чтобы включить их под правильным путем. Я не мог заставить его работать с дочерним модулем, определяющим путь, но его наличие на родительском компьютере прекрасно работает (и совместимо с ленивой загрузкой).
В моем случае у меня было три уровня в такой иерархии:
- Корень (
/
)
- Редактор (
editor/:projectId
)
- Запрос (
query/:queryId
)
- Страница (
page/:pageId
)
- Фронт (
about
)
Следующие определения работают для меня для пути /editor/:projectId/query/:queryId
:
// app.routes.ts
import {editorRoutes} from './editor/editor.routes'
// Relevant excerpt how to load those routes, notice that the "editor/:projectId"
// part is defined on the parent
{
path: '',
children: [
{
path: 'editor/:projectId',
children: [...editorRoutes]
//loadChildren: '/app/editor/editor.module'
},
]
}
Маршруты редактора выглядят следующим образом:
// app/editor/editor.routes.ts
import {queryEditorRoutes} from './query/query-editor.routes'
import {pageEditorRoutes} from './page/page-editor.routes'
{
path: "", // Path is defined in parent
component : EditorComponent,
children : [
{
path: 'query',
children: [...queryEditorRoutes]
//loadChildren: '/app/editor/query/query-editor.module'
},
{
path: 'page',
children: [...pageEditorRoutes]
//loadChildren: '/app/editor/page/page-editor.module'
}
]
}
И последняя часть для QueryEditor выглядит следующим образом:
// app/editor/query/query-editor.routes.ts
{
path: "",
component : QueryEditorHostComponent,
children : [
{ path: 'create', component : QueryCreateComponent },
{ path: ':queryId', component : QueryEditorComponent }
]
}
Однако для выполнения этой работы общий Editor
должен импортировать и экспорт QueryEditor
, а QueryEditor
должен экспортировать QueryCreateComponent
и QueryEditorComponent
, поскольку они видны с импортом. В противном случае вы получите ошибки в строках Component XYZ is defined in multiple modules
.
Обратите внимание, что ленивая загрузка также отлично работает с этой настройкой, в этом случае дочерние маршруты не должны импортироваться, конечно.
Ответ 2
У меня была та же проблема.
Ответ здесь довольно хороший, используя loadChildren:
{
path: 'mypath',
loadChildren : () => myModule
}
https://github.com/angular/angular/issues/10958
Ответ 3
Я нашел способ решить эту проблему. В основном, я определяю свои маршруты так, как я привык, но на этот раз на верхнем уровне ребенка. Например, мой маршрут администратора:
const AdminRoutes: Routes = [
{
path: 'admin',
component: AdminComponent,
children: [
...setupRoutes
]
}
]
export const adminRouting = RouterModule.forChild(AdminRoutes)
Мой файл маршрутов настройки импортируется из подзоны, которая определяет собственные маршруты, включая больше детей. Уловка заключается в том, что этот файл экспортирует объект "Маршруты", а не результат RouterModule.forChild.
После этой установки я удалил маршруты дочернего и дочернего объектов из определений подмодулей. Затем мне пришлось экспортировать все компоненты, используемые в маршрутах, от каждого из подмодулей, как и Маркус, упомянутый выше. Как только я это сделал, маршруты начали работать так, как я хотел их.
Я не думаю, что мне действительно нравится это решение, так как мой родительский модуль слишком много знает о маршрутах дочерних модулей. Но, по крайней мере, это простой способ обойти его для RC5, и он не просачивает все мои компоненты повсюду. Я продолжу и отвечу Марку как ответ, так как он поставил меня на правильный путь.
Ответ 4
Я получил это, чтобы работать, и если вам действительно нужно отобразить все родительские компоненты в иерархии, я думаю, что мое решение намного более элегантно.
Ключом к пониманию моего подхода является то, что все маршруты, независимо от того, насколько глубоко вложены в модули, добавляются в корневой модуль. Быстрый пример, скажем, у нас есть DepartmentModule
и EmployeeModule
, которые мы хотели бы использовать для использования этого URL
/department/1/employee/2
в этот момент мы увидим детали сотрудника 2. Настройка маршрутов для department
в department.routing.ts
и employee
в employee.routing.ts
не будет работать так, как мы планировали, и вы заметите, что можете перейти к
/employee/2
из корневого компонента, а
/department/1/employee/2
произойдет сбой (маршрут не найден). Типичная конфигурация маршрута в этом сценарии будет выглядеть так:
export const departmentRoutes: Routes = [
{ path: 'department', component: DepartmentComponent, children: [
{ path: '', component: DepartmentsComponent },
{ path: ':id', component: DepartmentDetailsComponent }
]}
];
export const employeeRoutes: Routes = [
{ path: 'employee', component: EmployeeComponent, children: [
{ path: '', component: EmployeesComponent },
{ path: ':id', component: EmployeeDetailsComponent }
]}
];
и EmployeeModule
будут импортированы с помощью DepartmentModule
. Теперь, как я уже сказал, это не работает, к сожалению.
Однако, всего за одно изменение это будет:
export const employeeRoutes: Routes = [
{ path: 'department/:id/employee', component: EmployeeComponent, children: [
{ path: '', component: EmployeesComponent },
{ path: ':id', component: EmployeeDetailsComponent }
]}
];
Ловушка заключается в том, что DepartmentModule
больше не принимает активного участия, как только вы переходите к URL employee
, но вы все равно можете получить доступ к каждому параметру из ActivatedRoute
:
export class EmployeeDetailsComponent {
departmentId: number;
employeeId: number;
constructor(route: ActivatedRoute) {
route.parent.params.subscribe(params =>
this.departmentId= +params['id'])
route.params.subscribe(params =>
this.employeeId= +params['id']);
}
}
Интересно, должно ли это быть официальным подходом, но пока это работает для меня до следующего взрывающегося изменения команды Angular 2.
Ответ 5
Думаю, 2.0.0 rc5 сейчас не интересует. Но работает в Angular 4, может быть и раньше.
@NgModule({
imports: [
RouterModule.forRoot([
{path: "", redirectTo: "test-sample", pathMatch: "full"},
{
path: "test-sample",
loadChildren: () => TestSampleModule
}
])
],
exports: [RouterModule],
declarations: []
})
export class AppRoutingModule{}
@NgModule({
imports: [
RouterModule.forChild([{
path: "",
component: TestSampleComponent,
children: [
{path: "", redirectTo: "home", pathMatch: "full"},
{
path: "home",
loadChildren: () => HomeModule
},
{
path: "about",
loadChildren: () => AboutModule
}
]
}
])
],
exports: [RouterModule],
declarations: []
})
export class TestSampleRoutingModule {}
@NgModule({
imports: [RouterModule.forChild([{
path: "",
component: AboutComponent
}
])],
exports: [RouterModule]
})
export class AboutRoutingModule {}
Учитывайте на loadChildren: () => {...}
. Это не ленивая загрузка.
Подробнее см. feat: Поддержка иерархии NgModules sans Lazy Loading
Ответ 6
Когда вы используете ngModules и RC5, конфигурация маршрутизации вашего родительского модуля не должна ничего знать о маршрутизации дочерних модулей. Здесь вам нужно определить маршруты для своего родительского модуля.
Кроме того, вам необходимо импортировать дочерний модуль в родительский модуль.
В дочернем модуле вы должны определить свои маршруты следующим образом:
export const childRoutes: Routes = [
{
path: 'someChild',
component: SomeChildComponent,
children: [
{ path: '', component: SomeChildSubComponent1 },
{ path: 'comp1', component: SomeChildSubComponent1 },
{ path: 'comp2', component: SomeChildSubComponent2 }
]
}
];
Это позволит вам иметь URL-адрес/someParent/someChild/comp1 - и компоненты отображаются в соответствующем маршрутизаторе-выходе.
Обратите внимание: вам нужно объявить компонент для пустого пути. В противном случае вы не сможете перейти к детям.
Ответ 7
Используйте loadChildren
. Это нормально. Но когда вы перезапустите процесс сборки, вы получите ошибку сборки. Вы должны сопоставить экспортированный символ с loadChildren
.
import { ChildModule } from './child/child.module';
export function childRouteFactory() {
return ChildModule;
}
...
{
path: 'child',
loadChildren: childRouteFactory
}
...