70

我正在将我正在开发的应用程序升级到最新的 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
      ]
   }
]

在另一个文件中,作为子模块的一部分,我还将定义各个模块路由,即

export const UserRoutes: RouterConfig = [
    {
       path: "users",
       component: userComponent,
       children: [
           {path: "new-user", component: newUserComponent}
       ]
    }

]

这一切都很好。在升级到 Modules 的过程中,我将所有内容都移到了各自的路由文件中,所以现在这两个看起来更像这样

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)

完成所有这些后,我有一个导入 userRouting 的 UsersModule,然后是一个导入 adminRoutes 和 UsersModule 的 AdminModule。我的想法是,由于 UsersModule 是 AdminModule 的子模块,因此路由将按照以前的方式工作。不幸的是,事实并非如此,所以我最终得到的用户路线只是

/users/new-user 

代替

/admin/users/new-user

此外,因此,新用户组件不会加载到我的管理组件的路由器出口中,这会影响我的应用程序的样式和导航。

我一辈子都想不出如何将我的 UserModule 的路由引用为我的 AdminModule 的子级。我已经尝试过用旧方法来做这件事,并得到关于两个模块中的路由的错误。显然,由于这是新发布的,围绕其中一些案例的文档有点有限。

任何人都可以提供的任何帮助将不胜感激!

4

7 回答 7

57

好的,在周末的大部分时间里摆弄了这个之后,我终于让它运行起来了。最终对我有用的是执行以下操作:

  • Routes为您要路由的每个模块导出全部。不要导入任何子RouterModule.forChild()模块中的。
  • 导出从子模块定义中的子路由定义可见的每个组件。
  • 像往常一样导入(意味着 Typescriptimport关键字)所有子路由,并使用...运算符将​​它们合并到正确的路径下。我无法让它与定义路径的子模块一起使用,但是将它放在父模块上可以正常工作(并且与延迟加载兼容)。

就我而言,我在这样的层次结构中有三个级别:

  • 根 ( /)
    • 编辑器 ( 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需要导出QueryCreateComponentQueryEditorComponent因为这些在导入时是可见的。如果不这样做,您会出现类似Component XYZ is defined in multiple modules.

请注意,延迟加载也适用于此设置,在这种情况下,当然不应导入子路由。

于 2016-08-15T09:53:04.177 回答
35

我有同样的问题。

使用 loadChildren 的答案非常好:

          {
             path: 'mypath',
             loadChildren : () => myModule
          }

https://github.com/angular/angular/issues/10958

于 2016-10-22T22:10:47.793 回答
4

我认为 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: () => {...}. 这不是延迟加载。

详情参见:Support NgModules hierarchy sans Lazy Loading

于 2017-04-02T19:45:05.400 回答
1

我也让它工作,除非你真的需要渲染层次结构中的所有父组件,否则我认为我的解决方案要优雅得多。

理解我的方法的关键是,所有路由,无论在模块中嵌套多深,都被添加到根模块中。简单的例子,假设我们有一个DepartmentModule和一个EmployeeModule我们想使用这个 URL 导航到的

/department/1/employee/2

此时我们会看到员工 2 的详细信息。department为indepartment.routing.tsemployeein配置路线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 }
    ]}
];

并将EmployeeModuleDepartmentModule. 现在,就像我说的那样,不幸的是,这不起作用。

但是,只需进行一次更改,它将:

export const employeeRoutes: Routes = [
    { path: 'department/:id/employee', component: EmployeeComponent, children: [
        { path: '', component: EmployeesComponent },
        { path: ':id', component: EmployeeDetailsComponent }
    ]}
];

问题是,一旦您导航到URL,DepartmentModule它就不再活跃,但您仍然可以从以下位置访问每个参数:employeeActivatedRoute

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 团队的下一次重大更改。

于 2016-09-22T03:52:06.377 回答
1

我也找到了解决这个问题的方法。基本上,我按照以前的方式定义我的路线,但这次是在顶级子级别。例如我的管理路线:

const AdminRoutes: Routes = [
   {
      path: 'admin',
      component: AdminComponent,
      children: [
          ...setupRoutes
      ]
   }
]

export const adminRouting = RouterModule.forChild(AdminRoutes)

我的设置路线文件是从一个子区域导入的,该子区域定义了它自己的路线,包括更多的孩子。问题是该文件导出“Routes”对象而不是 RouterModule.forChild 结果。

设置完成后,我从子模块定义中删除了子路由和子子路由。然后我必须从每个子模块中导出路由中使用的所有组件,就像上面提到的 Marcus 一样。一旦我这样做了,这些路线就开始像我想要的那样工作。

我不认为我真的喜欢这个解决方案,因为我的父模块对子模块路由了解太多。但至少它是 RC5 绕过它的一种简单方法,并且它不会将我所有的组件泄漏到所有地方。我会继续将马库斯的答案标记为答案,因为他让我走上了正确的轨道。

于 2016-08-18T22:05:24.663 回答
0

使用loadChildren. 没关系。但是当你重新启动构建过程时,你会得到构建错误。您应该将导出的符号与loadChildren.

import { ChildModule } from './child/child.module';

export function childRouteFactory() {
  return ChildModule;
}

...
  {
    path: 'child',
    loadChildren: childRouteFactory
  }
...
于 2017-04-14T00:52:47.833 回答
0

当你使用 ngModules 和 RC5 时,你的父模块的路由配置不需要知道任何关于子模块路由的信息。您只需在此处定义父模块的路由。此外,您必须将子模块导入父模块。在子模块中,您必须以这种方式定义您的路线:

export const childRoutes: Routes = [
  {
    path: 'someChild',
      component: SomeChildComponent,
      children: [
        { path: '', component: SomeChildSubComponent1 },
        { path: 'comp1', component: SomeChildSubComponent1 },
        { path: 'comp2', component: SomeChildSubComponent2 }
      ]
  }
];

这将让你有一个像 /someParent/someChild/comp1 这样的 url - 并且组件显示在它们相应的路由器插座中。请注意:您必须为空路径删除组件。否则,您将无法导航到您的孩子。

于 2016-09-02T08:11:16.580 回答