简体   繁体   English

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

[英]Angular 2 (Final): resetConfig to add routes to lazy loaded routes

I'm trying to understand how to dynamically add routes to those from a lazy loaded module. 我试图了解如何动态添加路由到延迟加载模块的路由。 I have the core app, with routes: 我有核心应用程序,有路线:

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

In A.module I import routes from the "local" moduleA.routes.config.ts: 在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);

So far so good. 到现在为止还挺好。 Now, in ModuleADetailComponent I have a list of "additional modules", which I'll call plugins, for my webapp, which are developed separately and I want to be able to show in ModuleADetailComponent page. 现在,在ModuleADetailComponent中,我有一个“附加模块”列表,我将其称为插件,用于我的webapp,它们是单独开发的,我希望能够在ModuleADetailComponent页面中显示。 Therefore, the template for this component is something like this: 因此,此组件的模板是这样的:

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

Of course, plugins is a configuration loaded upon navigation to ModuleADetailComponent, so I don't know ahead of time which modules are configured and how many there are. 当然,插件是导航到ModuleADetailComponent时加载的配置,所以我不知道提前配置了哪些模块以及有多少模块。 Lastly, each of these plugins can be an NgModule (developed separately in a workbench environment). 最后,这些插件中的每一个都可以是NgModule(在工作台环境中单独开发)。

What I need is: how do I modify the router configuration, dynamically, to add children to the route defined in moduleA.routes.config.ts? 我需要的是:如何动态修改路由器配置,将子节点添加到moduleA.routes.config.ts中定义的路由? For example, if I have 2 plugins, I want to dynamically use router.resetConfig to have what I would have if moduleA.routes.config.ts was like this: 例如,如果我有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);

I hope I can achieve it, otherwise plugins will have to be developed without routing...but they can become big sub-modules which would benefit from navigation. 我希望我能实现它,否则插件必须在没有路由的情况下开发......但它们可以成为可以从导航中受益的大型子模块。

EDIT 27/09/2016 : I've assembled this plunkr: http://plnkr.co/edit/6aV5n5K5wdqdiYo49lZv . 编辑27/09/2016 :我已经组装了这个plunkr: http ://plnkr.co/edit/6aV5n5K5wdqdiYo49lZv。 What I am currently able to do is load components dynamically and add them to the application (see tab "Dynamic Modules"). 我目前能够做的是动态加载组件并将它们添加到应用程序(请参见“动态模块”选项卡)。 What I've also done is to use multiple named router-outlets, despite not finding any official documentation (see tab "Dynamic Routed"). 我还做的是使用多个命名路由器插座,尽管没有找到任何官方文档(请参阅“动态路由”选项卡)。 Despite the tab name, routes are known ahead of time. 尽管标签名称,但路线是提前知道的。

What I want to do is: dynamically load a configuration (the dynamicRoutes array in the DynamicRoutesComponent) and only after create one router-outlet per dynamic route and use resetConfig (or what it takes) to have this configuration: 我想要做的是:动态加载一个配置(DynamicRoutesComponent中的dynamicRoutes数组),并且只在每个动态路由创建一个路由器出口并使用resetConfig(或它需要什么)来进行此配置:

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

with one child per dynamic route. 每个动态路线有一个孩子。

Thanks in advance! 提前致谢!

First of all, the loadChildren property method must be supplied with the following format ( https://angular.io/docs/ts/latest/guide/router.html#!#asynchronous-routing ): 首先,必须使用以下格式提供loadChildren属性方法( https://angular.io/docs/ts/latest/guide/router.html#!#asynchronous-routing ):

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

As you see above, the module path and the module name are joined with the # char. 正如你看到的上面的module pathmodule name都加入与#字符。

In your case, you need to to modify your app.routes more or less as follows (not sure about your module/file names, and the plunkr sample does not reflect the names given in this question): 在您的情况下,您需要或多或少地修改您的app.routes如下(不确定您的模块/文件名,并且plunkr示例不反映此问题中给出的名称):

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

This was just an intro, now let's proceed to the solution of your problem. 这只是一个介绍,现在让我们继续解决您的问题。 As far as I read, you want to dynamically add child routes. 据我所知,您想要动态添加子路由。

You can dynamically provide child routes in your feature module by using the following code. 您可以使用以下代码在功能模块中动态提供子路由。

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
    }
  ],
  [...]
})

You had to provide same routes for ANALYZE_FOR_ENTRY_COMPONENTS token (as well as ROUTES token) otherwise you'll get the No component factory found for YOUR_COMPONENT. Did you add it to @NgModule.entryComponents? 您必须为ANALYZE_FOR_ENTRY_COMPONENTS令牌(以及ROUTES令牌)提供相同的路由,否则您将获得No component factory found for YOUR_COMPONENT. Did you add it to @NgModule.entryComponents?No component factory found for YOUR_COMPONENT. Did you add it to @NgModule.entryComponents? No component factory found for YOUR_COMPONENT. Did you add it to @NgModule.entryComponents? error. 错误。

However, this code might produce errors during AoT compilation. 但是,此代码可能会在AoT编译期间产生错误。 In this case, you'll need to provide a factory instead of a value for ROUTES token. 在这种情况下,您需要提供factory而不是ROUTES令牌的value However, you won't be able to provide a factory for ANALYZE_FOR_ENTRY_COMPONENTS token - it does only accept useValue (see https://github.com/angular/angular/blob/03e855ae8f9e9b86251320c7551a96092bd8b0c4/modules/%40angular/compiler/src/metadata_resolver.ts#L926 ). 但是,您将无法为ANALYZE_FOR_ENTRY_COMPONENTS令牌提供factory - 它只接受useValue (请参阅https://github.com/angular/angular/blob/03e855ae8f9e9b86251320c7551a96092bd8b0c4/modules/%40angular/compiler/src/metadata_resolver。 ts#L926 )。

In that case, use the following code on your feature module: 在这种情况下,请在功能模块上使用以下代码:

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...]
  [...]
})

Note : Using Observables/Promises to provide routes is not a reliable solution, hence the Angular router expects Route[] or Routes , but an HTTP request can only return an Observable/Promise (The Angular app gets initialized, but the retrieval process of routes still goes on using Observables/Promises) (see https://github.com/ngx-i18n-router/config-loader#readme ). 注意 :使用Observables / Promises提供路由不是一个可靠的解决方案,因此Angular路由器需要Route[]Routes ,但HTTP请求只能返回Observable / Promise(Angular应用程序被初始化,但路由的检索过程)仍然继续使用Observables / Promises)(参见https://github.com/ngx-i18n-router/config-loader#readme )。

Use such functions which return Route[] or Routes . 使用返回Route[]Routes函数。

Meantime, you might check the module file of @ngx-i18n-router/core (an internationalization utility for Angular, benefits from dynamic routes) and this example-app as its implentation. 同时,您可以检查@ ngx-i18n-router / core模块文件 (Angular的国际化实用程序,从动态路由中获益)以及此example-app作为其实现。

Would it be possible to do something like this ? 是否有可能做这样的事情这样 Basically, in the constructor of a component you have access to activatedRoute.routeConfig.children , with which you should be able to add more children to that array. 基本上,在组件的构造函数中,您可以访问activatedRoute.routeConfig.children ,您应该可以使用该元素向该数组添加更多子项。

If you are trying to get data from another source, you should be able to set this up in the subscriber part of an Observable . 如果您尝试从其他源获取数据,则应该能够在Observablesubscriber部分中进行设置。 I'm thinking something like this: 我在想这样的事情:

@Component({
  selector: 'app-module-a-detail',
  templateUrl: './module-a-detail.component.html'
})
export class ModuleADetailComponent {
  constructor(
    private activatedRoute: ActivatedRoute) {

    const childRoutes: Routes = this.activatedRoute.routeConfig.children;

    this.pluginService.getPlugins({
      .subscribe(map(plugin => {
        // build up my additional childRoute here
        childRoutes.push(newChildRoute);
      }))
    );
  }
}

Actually the problem to me is how costructing newChildRoute : 实际上我遇到的问题是如何构建newChildRoute

before I had something like: 在我之前有这样的事情:

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

to create new objects {} to change my actual this.router.config . 创建新对象{}来改变我的实际this.router.config

in this way calling this.router.resetConfig(this.router.config); 以这种方式调用this.router.resetConfig(this.router.config); should work.... 应该管用....

but replacing "loadChildren": moduleURLFromFile + "#" + moduleNameFromFile 但是替换“loadChildren”:moduleURLFromFile +“#”+ moduleNameFromFile

with

"loadChildren": () => import(moduleURLFromFile ).then(m => m.moduleNameFromFile) “loadChildren”:()=> import(moduleURLFromFile).then(m => m.moduleNameFromFile)

seems not working. 似乎不起作用。

hope this better clarify 希望这更好地澄清

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM