如何作为模块的子级路由至模块-Angular 2 RC 5


68

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

在较早的路由器版本中,使用“儿童”可以轻松完成此操作

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}
       ]
    }

]

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

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)

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

/users/new-user 

代替

/admin/users/new-user

此外,由于这个原因,新用户组件不会加载到我的admin组件的路由器出口中,这会打乱我的应用程序的样式和导航。

我一生都无法提出如何将UserModule的路由作为AdminModule的子级引用。我尝试用旧方法执行此操作,并得到有关两个模块中路由的错误。显然,由于它是新发布的,因此有关某些情况的文档有些局限。

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


1
loadChildren路由上有一个属性,可以明确提及模块。文档只在延迟加载的情况下谈论它...
Marcus Riemer


我发现Todd Motto撰写的有关Angular Router的文章非常有用。loadChildren也很好解释。
辛里奇

Answers:


55

好吧,在周末的大部分时间里摆弄这些东西之后,我就开始运行了。最终对我有用的是执行以下操作:

  • 导出所有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需要进口出口QueryEditorQueryEditor需求的出口QueryCreateComponentQueryEditorComponent,因为这些都是与进口可见。不这样做会导致您出现错误Component XYZ is defined in multiple modules

请注意,延迟加载在此设置下也可以正常工作,在这种情况下,当然不应导入子路由。


1
这看起来很有希望,感谢您投入的时间。您能否澄清一下模块定义以及从路由文件中导出的内容到底是什么?您要导出Routes []还是要从路由文件中导出RouterModule.forChild()?以及如何在模块中导出/导入它们以使其可见?到目前为止,我的尝试导致两次定义了RouterOutlet的错误,然后又导致了在模块中将Routes []导出为意外的[object,Object]时出现的问题。
约翰·阿克曼

3
哦,对不起。。。我以某种方式阅读了您的评论,然后没有回音。您可以在bitbucket.org/marcusriemer/esqulino/src/上
Marcus Riemer

我花了一些时间来得到这个答案。感谢您的澄清和详细的答复。有机会获得指向角度文档的链接吗?
eagle.dan.1349 16-10-11

我不太确定您在此答案中期望得到什么样的链接?
Marcus Riemer

1
如果它包括一个小矮人,这个答案将是很棒的
Zze

35

我有同样的问题。

使用loadChildren,这里的答案非常好:

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

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


3
该链接特别有用。
Zze

这比公认的答案更好。在这里,我可以将子组件保留在模块中,而不必将其暴露给父模块。
mmey

我在使用此工具时遇到很多问题。当您使用JIT模式编译时,它可以工作。但是当您建立构建AOT模式时根本不起作用。AOT模式不支持这种模块初始化。
m.rufca,

3

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

有关详细信息,请参见壮举:支持NgModules层次结构,无延迟加载


1

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

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

export const adminRouting = RouterModule.forChild(AdminRoutes)

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

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

我认为我不喜欢这种解决方案,因为我的父模块对子模块路由了解得太多。但是,至少对于RC5而言,这是一种解决问题的简便方法,并且它不会泄漏我所有的组件。我会继续并将Marcus的答案标记为答案,因为他使我处于正确的轨道上。


约翰,您好,您的方法行得通,但是如何处理模块延迟加载?看来采用这种方法,您不能延迟加载其他模块
Alex G

1

我也可以使用它,除非您确实需要呈现层次结构中的所有父组件,否则我认为我的解决方案要优雅得多。

理解我的方法的关键是,无论模块中嵌套的深度如何,所有路由都将添加到根模块中。举个简单的例子,假设我们有一个DepartmentModule和一个EmployeeModule我们要使用此URL导航的

/department/1/employee/2

此时,我们将看到员工2的详细信息。路由的配置departmentdepartment.routing.ts,并employeeemployee.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一旦导航到employeeURL,就不再起作用,但是您仍然可以从中访问每个参数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团队进行下一次重大更改为止。


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-组件将显示在其相应的路由器出口中。请注意:您必须为空路径放置一个组件。否则,您将无法导航至孩子。


1
这仅适用于第一层嵌套。对于所有后续级别,路由都将添加到根模块,并且无法通过其父级访问。
Thorsten Westheider

High Torsten,很遗憾,您是对的。通过在父路径之前添加路径来修改路由对象的路径信息,可以接触到组件。但是您仍然不会在正确的路由器插座中看到它。这似乎也是您解决方案的问题。可能是错误吗?您知道吗,是否已经存在与此相关的问题?
韦斯特

我认为这是设计使然,您可以使用延迟加载来解决它,无论如何这可能是一个更好的解决方案。
Thorsten Westheider

这个问题有什么进展吗?我只是在2.0.0版中遇到了同样的问题。@ThorstenWestheider
Kinorsi '16

0

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

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

export function childRouteFactory() {
  return ChildModule;
}

...
  {
    path: 'child',
    loadChildren: childRouteFactory
  }
...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.