Angular 2(Final):resetConfig将路由添加到延迟加载的路由

时间:2016-09-19 12:06:12

标签: dynamic angular module lazy-loading router

我正在尝试了解如何动态地将路由添加到延迟加载的模块中。 我有核心应用程序,路线:

export const routes = [{
    path: "",
    component: HomeComponent
}, {
    path: "moduleA",
    loadChildren: "app/moduleA/A.module"
}];

在A.module中我从“local”moduleA.routes.config.ts导入路由:

const routes = [{
    path: "",
    component: ModuleAHomeComponent,
    children: [
        { path: "", component: ModuleAListComponent },
        { path: ":id", component: ModuleADetailComponent }
    ]
}];
export const routing = RouterModule.forChild(routes);

到目前为止一切顺利。现在,在ModuleADetailComponent中,我有一个“附加模块”列表,我将其称为插件,用于我的webapp,它们是单独开发的,我希望能够在ModuleADetailComponent页面中显示。 因此,此组件的模板如下所示:

<div *ngFor="let plugin of plugins">
    <div class="header">{{ plugin.name }}</div>
    <router-outlet name="*plugin.name*">*LOAD MODULE HERE*</router-outlet>
</div>

当然,插件是导航到ModuleADetailComponent时加载的配置,因此我不知道提前配置了哪些模块以及有多少模块。 最后,这些插件中的每一个都可以是NgModule(在工作台环境中单独开发)。

我需要的是:如何动态修改路由器配置,将子节点添加到moduleA.routes.config.ts中定义的路由? 例如,如果我有2个插件,我想动态使用router.resetConfig,如果moduleA.routes.config.ts是这样的话,我将拥有它:

const routes = [{
    path: "",
    component: ModuleAHomeComponent,
    children: [
        { path: "", component: ModuleAListComponent },
        { 
            path: ":id",
            component: ModuleADetailComponent,
            children: [
                {
                    path: "plugin1",
                    loadChildren: "app/plugins/plugin1.module",
                    outlet: "plugin1"
                },
                {
                    path: "plugin2",
                    loadChildren: "app/plugins/plugin2.module",
                    outlet: "plugin2"
                }                
            ]
        }
    ]
}];
export const routing = RouterModule.forChild(routes);

我希望我能实现它,否则插件必须在没有路由的情况下开发......但它们可以成为可以从导航中受益的大型子模块。

编辑2016年9月27日:我收集了这个傻瓜:http://plnkr.co/edit/6aV5n5K5wdqdiYo49lZv。 我目前能够做的是动态加载组件并将它们添加到应用程序(请参见“动态模块”选项卡)。 我还做的是使用多个命名路由器插座,尽管没有找到任何官方文档(请参阅“动态路由”选项卡)。尽管有标签名称,但提前知道路线。

我想要做的是:动态加载配置(DynamicRoutesComponent中的dynamicRoutes数组),并且只有在每个动态路由创建一个路由器出口并使用resetConfig(或它需要什么)才能进行此配置:

{
  path: "dynamic-routed",
  component: DynamicRoutesComponent,
  children: [
    { path: "", component: EmptyComponent },
    { path: "component1", component: Component1, outlet: "component1" },
    { path: "component2", component: Component2, outlet: "component2" }
  ]
}

每个动态路线有一个孩子。

提前致谢!

3 个答案:

答案 0 :(得分:5)

首先,必须使用以下格式(https://angular.io/docs/ts/latest/guide/router.html#!#asynchronous-routing)提供loadChildren属性方法:

{
  path: 'admin',
  loadChildren: 'app/admin/admin.module#AdminModule',
},

如上所述,module pathmodule name#字符一起加入。

在您的情况下,您需要或多或少地修改您的app.routes如下(不确定您的模块/文件名,并且plunkr示例不反映此问题中给出的名称):

export const routes = [{
    path: "",
    component: HomeComponent
}, {
    path: "moduleA",
    loadChildren: "app/moduleA#ModuleA"
}];

这只是一个介绍,现在让我们继续解决您的问题。据我所知,你想动态添加子路由。

您可以使用以下代码在功能模块中动态提供子路由。

import {ROUTES} from '@angular/router/src/router_config_loader';
import {ANALYZE_FOR_ENTRY_COMPONENTS} from '@angular/core';

[...]
let routesToAdd = ... // provide your routes here

@NgModule({
  [...]
  imports: [RouterModule.forChild([])] // Empty on purpose
  [...]
  providers: [
    {
      provide: ROUTES,
      useValue: routesToAdd,
      multi: true
    },
    {
      provide: ANALYZE_FOR_ENTRY_COMPONENTS,
      useValue: routesToAdd, // provide them here too
      multi: true
    }
  ],
  [...]
})

您必须为ANALYZE_FOR_ENTRY_COMPONENTS令牌(以及ROUTES令牌)提供相同的路由,否则您将收到No component factory found for YOUR_COMPONENT. Did you add it to @NgModule.entryComponents?错误。

但是,此代码可能会在AoT编译期间产生错误。在这种情况下,您需要为factory令牌提供value而不是ROUTES。但是,您无法为factory令牌提供ANALYZE_FOR_ENTRY_COMPONENTS - 它只接受useValue(请参阅https://github.com/angular/angular/blob/03e855ae8f9e9b86251320c7551a96092bd8b0c4/modules/%40angular/compiler/src/metadata_resolver.ts#L926)。

在这种情况下,请在功能模块上使用以下代码:

import {ROUTES} from '@angular/router/src/router_config_loader';

[...]
let routesToAdd = ... // provide your routes here

@NgModule({
  [...]
  imports: [RouterModule.forChild([])] // Empty on purpose
  [...]
  providers: [
    {
      provide: ROUTES,
      useFactory: (getRoutesFromSomewhere),
      //deps: [SomeService, SOME_TOKEN] // deps is optional, in the case you need no params - delete it; otherwise pass 'em
      multi: true
    }
  ],
  entryComponents: [CompA, CompB, CompC, etc...]
  [...]
})

注意:使用Observables / Promises提供路由不是一个可靠的解决方案,因此Angular路由器需要Route[]Routes,但HTTP请求只能返回Observable / Promise(Angular应用程序被初始化,但路由的检索过程仍然使用Observables / Promises)(参见https://github.com/ngx-i18n-router/config-loader#readme)。

使用返回Route[]Routes

的此类函数

同时,您可以查看module file@ngx-i18n-router/core(Angular的国际化实用程序,动态路由的好处)以及此example-app作为其实现。

答案 1 :(得分:0)

是否可以做类似this的事情?基本上,在组件的构造函数中,您可以访问activatedRoute.routeConfig.children,使用它应该可以向该数组添加更多子项。

如果您尝试从其他来源获取数据,则应该能够在subscriber的{​​{1}}部分中进行设置。我在想这样的事情:

Observable

答案 2 :(得分:0)

实际上,我遇到的问题是如何构建newChildRoute

在我有类似的东西之前:

         "path": pathFromFile,
         "outlet": outletFromFile,
         "data": dataFromFile,
         "component": HostComponent, (my custom host component for named outlet)
         "loadChildren": moduleURLFromFile + "#" + moduleNameFromFile

创建新对象{}来更改我的实际this.router.config

以这种方式调用this.router.resetConfig(this.router.config);应该可以。...

但要更换 “ loadChildren”:moduleURLFromFile +“#” + moduleNameFromFile

使用

“ loadChildren”:()=> import(moduleURLFromFile)。然后(m => m.moduleNameFromFile)

似乎不起作用。

希望可以更好地阐明