web-dev-qa-db-ja.com

RouterModule.forRoot(ROUTES)とRouterModule.forChild(ROUTES)

これら2つの違いは何ですか、またそれぞれの使用例は何ですか?

docs はあまり役に立ちません。

forRootは、すべてのディレクティブ、指定された経路、およびルーターサービス自体を含むモジュールを作成します。

forChildは、すべてのディレクティブと指定された経路を含むモジュールを作成しますが、ルーターサービスは含みません。

私の漠然とした推測は、1つは「メイン」モジュール用で、もう1つはインポートされたモジュール用です(すでにメインモジュールからサービスを利用できるため)、しかし実際にはユースケースを考えることはできません。

76
VSO

この記事を読むことを強くお勧めします。

プロバイダとのモジュール

モジュールをインポートするときは、通常、モジュールクラスへの参照を使用します。

@NgModule({
    providers: [AService]
})
export class A {}

-----------------------------------

@NgModule({
    imports: [A]
})
export class B

このようにして、モジュールAに登録されているすべてのプロバイダがルートインジェクタに追加され、アプリケーション全体で利用可能になります。

しかし、このようにプロバイダにモジュールを登録する別の方法があります。

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProviders = {
    ngModule: A,
    providers: [AService]
};

----------------------

@NgModule({
    imports: [moduleWithProviders]
})
export class B

これは前のものと同じ意味を持ちます。

あなたはおそらく、遅延ロードされたモジュールがそれら自身のインジェクタを持っていることを知っています。そのため、アプリケーション全体で利用できるようにAServiceを登録したいが、遅延ロードされたモジュールだけが利用できるようにいくつかのBServiceを登録したいとします。このようにモジュールをリファクタリングすることができます。

@NgModule({
    providers: [AService]
})
class A {}

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [AService]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [BService]
};

------------------------------------------

@NgModule({
    imports: [moduleWithProvidersForRoot]
})
export class B

// lazy loaded module    
@NgModule({
    imports: [moduleWithProvidersForChild]
})
export class C

これでBServiceは子の遅延ロードされたモジュールでのみ利用可能になり、AServiceはアプリケーション全体で利用可能になります。

上記のように書き出したモ​​ジュールとして書き直すことができます。

@NgModule({
    providers: [AService]
})
class A {
    forRoot() {
        return {
            ngModule: A,
            providers: [AService]
        }
    }

    forChild() {
        return {
            ngModule: A,
            providers: [BService]
        }
    }
}

--------------------------------------

@NgModule({
    imports: [A.forRoot()]
})
export class B

// lazy loaded module
@NgModule({
    imports: [A.forChild()]
})
export class C

それはRouterModuleとどのように関連していますか?

両方とも同じトークンを使用してアクセスされるとします。

export const moduleWithProvidersForRoot = {
    ngModule: A,
    providers: [{provide: token, useClass: AService}]
};

export const moduleWithProvidersForChild = {
    ngModule: A,
    providers: [{provide: token, useClass: BService}]
};

遅延ロードされたモジュールからtokenを要求したときに別々の設定をすると、BServiceが予定通りに得られます。

RouterModuleはROUTESトークンを使用して、モジュールに固有のすべての経路を取得します。このモジュール内で遅延ロードされたモジュールに固有のルートを利用可能にしたいので(BServiceに似ています)、遅延ロードされた子モジュールに対して異なる設定を使用します。

static forChild(routes: Routes): ModuleWithProviders {
    return {
        ngModule: RouterModule, 
        providers: [{provide: ROUTES, multi: true, useValue: routes}]
    };
}

ドキュメンテーションには、この区別の目的が何であるかが明確に記載されています。 https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root

ルートアプリケーションモジュールAppModuleでのみforRootを呼び出します。他のモジュール、特に遅延ロードされたモジュールで呼び出すと、意図に反し、実行時エラーが発生する可能性があります。

結果をインポートすることを忘れないでください。他の@NgModuleリストに追加しないでください。

すべてのアプリケーションには、メインルーティングサービスをforRootで初期化する必要がある開始点(ルート)が1つだけあり、特定の「子」機能のルートはforChildで登録する必要があります。これはアプリケーションの開始時にロードする必要がないサブモジュールや遅延ロードされたモジュールに非常に役立ちます。そして@Harry Ninhが言ったようにそれらは新しいサービスの登録の代わりにRouterServiceを再利用するように言われます。

23
Marcin

答えは正しいと思いますが、何かが足りないと思います。
欠けているものは、「なぜ、そしてそれが何を解決するのか」です。
じゃあ始めよう。

まず、情報をいくつか挙げましょう。

すべてのモジュールがルートサービスにアクセスできます。
したがって、遅延ロードされたモジュールでもapp.moduleで提供されていたサービスを使うことができます。
遅延ロードされたモジュールが、アプリモジュールが既に提供していたサービスを自分自身に提供するとどうなりますか? 2個のインスタンスがあります。
それは問題ではありませんが、時にはそれはです。
どうすれば解決できますか?単にそのプロバイダのモジュールを遅延ロードされたモジュールにインポートしないでください。

物語の終わり。

これは、遅延ロードされたモジュールが(非遅延ロードされたモジュールとは対照的に)独自のインジェクションポイントを持っていることを示すためだけのものでした。

しかし、shared(!)モジュールがprovidersを宣言し、そのモジュールがlazy app.moduleによってインポートされるとどうなりますか?繰り返しますが、2つのインスタンスがあります。

それでは、共有モジュールPOVでこれをどのように解決できるでしょうか。 providers:[]を使うにはnotという方法が必要です。どうして ?それらは、lazyとapp.moduleの両方に自動的にインポートされるため、それぞれが異なるインスタンスを持つことになるので、これは望ましくありません。

providers:[]を持たない共有モジュールを宣言することはできますが、それでもprodiversを提供することになります(ごめんなさい:))。

どうやって ?このような :

enter image description here

注意、プロバイダはありません。

しかし

  • app.moduleがPOV of serviceで共有モジュールをインポートするとき、どうなりますか?何もない。

  • lazyモジュールがPOV of serviceで共有モジュールをインポートするとどうなりますか?何もない。

慣習による手動機構の入力:

あなたは、写真の中のプロバイダーがservice1service2を持っていることに気付くでしょう

これにより、遅延ロードされたモジュールにはservice2を、非遅延モジュールにはservice1をインポートすることができます。 (咳...ルーター....咳

ところで、だれもあなたがlazyモジュールの中でforRootを呼ぶのを止めていません。 app.moduleもそうするべきであるので、あなたは2つのインスタンスを持つでしょう - それで怠け者のモジュールでそれをしないでください

app.moduleforRootを呼び出す(そして誰もforchildを呼び出さない)のであれば - それでも構いませんが、ルートインジェクタはservice1のみを持ちます。 (すべてのアプリで利用可能)

では、なぜそれが必要なのでしょうか。私は言うでしょう:

forRootforChildの慣習により、共有モジュールは、その異なるプロバイダを積極的なモジュールや遅延モジュールで使用するためにsplitできるようになります。繰り返します:convention

それでおしまい。

待つ !!シングルトンについての単一の単語ではない?それで、なぜ私はどこでもシングルトンを読みますか?

ええ - それは上の文に隠されています^

共有モジュールは、forRootとforChildを介して、異なるモジュールを積極的なモジュールと遅延モジュールで使用するためにsplitすることができます。

convention(!!!)は、シングルトンになることを可能にします - あるいは、より正確に - あなたが規則に従わない場合 - あなたはNOTシングルトンを取得しないでしょう。
app.moduleforRootをロードするだけの場合、app.moduleforRootを呼び出すだけでよいので、インスタンスは1つしか得られません。
ところで - この時点であなたはforChildを忘れることができます。遅延ロードされたモジュールはforRootを呼び出してはいけません - だからシングルトンのPOVで安全です。

forRootとforChildは壊れないパッケージの1つではありません。遅延モジュールの機能を持たずにapp.moduleにのみロードされ、新しいサービスを作成せずに独自のサービスを持つRootを呼び出す意味がないということです。シングルトンになる。

この規約はあなたにforChildと呼ばれる素晴らしい能力を与えます - 「遅延ロードされたモジュールのためだけのサービス」を消費する。

これがデモです。ルートプロバイダは正の数、レイジーロードされたモジュールは負の数を生成します。

19
Royi Namir

AppRoutesにサイト内のさまざまな機能(admin crud、user crud、book crud)へのパスが含まれていて、それらを分離したい場合は、単にそれを行うことができます。

 imports: [
    BrowserModule, HttpModule,
    AppRoutingModule,
    RouterModule.forRoot(categoriesRoutes),
    RouterModule.forRoot(auteursRoutes),
  ],

ルートの場合:

const auteursRoutes:Routes=[
  {path:'auteurs/ajouter',component:CreerAuteurComponent},
]
const categoriesRoutes: Routes = [


  {path:'categories/consulter',component:ConsultercategoriesComponent},
  {path:'categories/getsouscategoriesbyid/:id',component:GetsouscategoriesbyIDComponent},
  {path:'categories/ajout',component:CreerCategorieComponent},
 {path:'categories/:id',component:ModifiercategorieComponent},
 {path:'souscategories/ajout/:id',component:AjoutersouscategorieComponent},
 {path:'souscategories/lecture/:id1',component:SouscategoriesComponent},
 {path:'souscategories/modifier/:id1',component:ModifiersupprimersouscategorieComponent},
  {path:'uploadfile',component:UploadfileComponent},
  {path:'categories',component:ConsultercategoriesComponent},



]
0