Подтвердить что ты не робот

Как проложить маршрут к модулю в качестве дочернего модуля - 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. Я попытался сделать это по-старому и получить ошибки о маршрутах, находящихся в двух модулях. Очевидно, так как это недавно выпущено, документация по некоторым из этих случаев немного ограничена.

Любая помощь, которую любой может предоставить, будет с благодарностью!

4b9b3361

Ответ 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
  }
...