【问题标题】:How to route to a Module as a child of a Module - Angular 2 RC 5如何作为模块的子级路由到模块 - Angular 2 RC 5
【发布时间】:2016-08-10 17:03:30
【问题描述】:

我正在将我正在开发的应用程序升级到最新的 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 的子级。我已经尝试过用旧方法来做这件事,并得到关于两个模块中的路由的错误。显然,由于这是新发布的,围绕其中一些案例的文档有点有限。

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

【问题讨论】:

标签: angular angular2-routing angular2-modules angular2-router3


【解决方案1】:

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

  • 为您要路由的每个模块导出所有Routes。不要在子模块中导入任何RouterModule.forChild()。
  • 导出子模块定义中子路由定义中可见的每个组件。
  • 像往常一样导入(意味着 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 的错误。

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

【讨论】:

  • 这看起来很有希望,我很感谢您投入的时间。您能否澄清一下您的模块定义,以及您从路由文件中导出的具体内容是什么?您是在导出 Routes[] 还是从路由文件中导出 RouterModule.forChild()?您在哪里导出/导入模块中的那些以使它们可见?到目前为止,我的尝试导致了关于 RouterOutlet 被定义两次的错误,然后尝试将模块中的 Routes[] 导出为意外的 [object, Object] 被导出。
  • 哦,对不起......我以某种方式阅读了您的评论,然后没有回答它。您可以在 bitbucket.org/marcusriemer/esqulino/src/… 看到我最终完成的整个设置
  • 我花了一些时间来得到这个答案。感谢您的澄清和详细回答。有机会获得角度文档的链接吗?
  • 我不太确定你在这个答案中期望什么样的链接?
  • 如果它包含一个 plunkr,这个答案会很棒
【解决方案2】:

我遇到了同样的问题。

这里的答案很好用 loadChildren :

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

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

【讨论】:

  • 那个链接特别有用。
  • 这比接受的答案要好。在这里,我可以将子组件留在模块中,而不必将它们暴露给父模块。
  • 我在使用它时遇到了很多问题。当您使用JIT 模式编译时,它可以工作。但是,当您在AOT 模式上进行构建时,它根本不起作用。 AOT模式不支持这种模块初始化。
【解决方案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: () => {...}。这不是延迟加载。

详情请见feat: Support NgModules hierarchy sans Lazy Loading

【讨论】:

    【解决方案4】:

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

    const AdminRoutes: Routes = [
       {
          path: 'admin',
          component: AdminComponent,
          children: [
              ...setupRoutes
          ]
       }
    ]
    
    export const adminRouting = RouterModule.forChild(AdminRoutes)
    

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

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

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

    【讨论】:

    • 嗨,John,您的方法确实有效,但是您如何处理模块延迟加载?看来用这种方法,你不能懒加载其他模块
    【解决方案5】:

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

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

    /department/1/employee/2
    

    此时我们会看到员工 2 的详细信息。为department.routing.ts 中的department 和employee.routing.ts 中的employee 配置路由不会按照我们预期的方式工作,您会注意到您可以导航到

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

    问题是,当您导航到 employee URL 时,DepartmentModule 不再积极参与,但您仍然可以从 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 团队的下一次重大更改。

    【讨论】:

      【解决方案6】:

      当你使用 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 - 并且组件显示在它们相应的路由器插座中。 请注意:您必须为空路径删除组件。否则,您将无法导航到您的孩子。

      【讨论】:

      • 这仅适用于第一级嵌套。对于所有后续级别,路由被添加到根模块并且无法通过其父模块访问。
      • 高托斯滕,不幸的是你是对的。当您通过添加父路径来修改路由对象的路径信息时,您可以访问您的组件。但是您仍然不会在正确的路由器插座中看到它。这似乎也是您的解决方案的问题。可能是一个错误?你知道,如果这已经存在问题了吗?
      • 我认为这是设计使然,您可以使用延迟加载来解决它,这可能是一个更好的解决方案。
      • 这个问题有什么进展吗?我刚刚在 2.0.0 版本中遇到了同样的问题。 @ThorstenWestheider
      【解决方案7】:

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

      import { ChildModule } from './child/child.module';
      
      export function childRouteFactory() {
        return ChildModule;
      }
      
      ...
        {
          path: 'child',
          loadChildren: childRouteFactory
        }
      ...
      

      【讨论】:

        猜你喜欢
        • 2017-01-07
        • 2018-08-13
        • 2017-01-10
        • 1970-01-01
        • 2018-11-30
        • 1970-01-01
        • 2018-07-04
        • 1970-01-01
        • 2017-07-04
        相关资源
        最近更新 更多