模块中子应用程序之间的Angular2路由

时间:2016-10-26 17:03:41

标签: angular angular2-routing

我将Angular 2.1用于具有多个子模块的大型应用程序,每个子模块定义按功能组织的子应用程序。顶级模块通过导入每个子应用程序的路由等,为整个应用程序配置RouterModule以及所有子路由。因此,从子应用程序的角度来看,它相对于顶层的任何路由进行路由。级别应用程序设置路由,但是子应用程序没有直接明确地知道它的主要路由实际是什么。

其中一些子应用程序具有在另一个子应用程序中更完全定义/控制的实体的摘要面板。从概念上讲,模块的设置如下:

Module 1:
    Imports Module 2
    Routes for Module 1
    Component1A
    App1View (contains Component1A, M2SummaryComponent)

Module 2:
    Routes for Module 2 (one exported as APP2_VIEW_ROUTE, type Route)
    Component2A
    Component2B
    M2SummaryComponent
    App2View (contains Component2A, Component2B)
    ...etc.

我正在寻找一种设计模式,借此可以编写M2SummaryComponent链接到其自己模块中的路径,同时在模块1的App1View中实例化,而无需硬编码或重新组装以某种方式,手动路线。

我曾希望这是一个普遍存在的问题,Angular团队可能会使用像router.navigate([APP2_VIEW_ROUTE, ...other params])这样的东西,其中一个人可以简单地传递用于配置与所需路径相关的RouterModule的路由对象。看一下源代码,但这似乎不是一个选择。相反,我们有ActivatedRoute的例子。

ActivatedRoute(下面的this.route)面临的问题是它将与App1View相关。因此,尝试使用router.navigate(['m2SpecialId'],{relativeTo: this.route})是一个非首发,因为它将相对于将我们带到App1View的路径,而不是返回到模块2的首选App2View路径。

就我所知,围绕这些问题的唯一其他的,有点优雅的路线(双关语)是使每个子应用程序的模块可以作为ModuleWithProviders导入,以便可选地,可以通知应用于其状态的顶级路由的模块。然后编写辅助函数,使用其定义的路由组合特定于该子应用程序的URI。

这感觉非常糟糕......就像框架中已经存在解决方案或设计模式一样,因此这个问题。

问题:

是否有使用Angular2路由器的设计模式,允许导入其他模块的组件干净地引用自己模块的预配置路由,同时保持灵活的顶级路由定义?

2 个答案:

答案 0 :(得分:5)

如果要通过链接访问M1中的M2Component,则应使用RouterModule,不要在module1中导入module2。

在module1内部使用

RouterModule.forRoot([
    {
        path: 'module2',
        loadChildren: 'path-of-module2/module2.module#Module2Module'
    }
])

并在module2中

RouterModule.forChild([
    {
        path: '',
        component: Module2Component
    }
])

现在您可以从路线' / module2'。

打开Module2Component

答案 1 :(得分:0)

这里的解决方案我说的听起来非常模板化。它要求您使用一对不透明的令牌设置子应用程序模块:一个用于您的URI,另一个用于防止重新配置该URI。

import {
    NgModule,
    OpaqueToken,
    ModuleWithProviders,
    Optional,
    SkipSelf,
    Inject
} from '@angular/core';

export const ROOT_URI = new OpaqueToken('ROOT_URI');
export const URI_GUARD = new OpaqueToken('URI_GUARD');

接下来,您需要定义NgModule

@NgModule({ /** ... as before ... */ })
export class SubApp1Module {
    static configure(uri: string): ModuleWithProviders {
        return {
            ngModule: SubApp1Module,
            providers: [
                { provide: ROOT_URI, useValue: uri },
                { provide: URI_GUARD, useFactory: provideGuard,
                  deps: [[ Object, new Optional(), new SkipSelf() ]] }
            ]
        };
    }

    constructor(@Optional() @Inject(URI_GUARD) guard: any) { /** */ }
}

provideGuard功能:

export function provideGuard(something: any): any {
    if (!something) {
        return 'guarded';
    } else {
        throw new Error('Do not attempt to configure this module more than once.');
    }
}

在您要导入此模块并配置最终将您进入此子应用程序的RouterModule路由的模块中,您将其添加到导入:imports: [ ..., SubApp1Module.configure(SPECIAL_ROOT_URL), ...]

在SubApp1Module中的任何组件/指令中,您可以通过注入获取此模块的ROOT_URI

import { Inject } from '@angular/core';
import { ROOT_URI } from './whatever/local/export/location';

// Down at the constructor
constructor(@Inject(ROOT_URI) rootUri: string) {
    console.log('This is my rootUri: ' + rootUri);
}

现在,这可行,当然您可以根据需要使用@Optional?来允许注入默认值。如果您决定走这条路线,这也适用于注入解决路线的服务或工厂等。

在某些方面,这感觉就像Angular Way™(即,这样做)。然而,正如您所看到的那样,只是允许模块中的实体路由到他们自己的模块中,尽管在没有硬编码路径的情况下将其实例化为另一个模块中的Component,等等