it-swarm.com.de

RouterModule.forRoot (ROUTES) vs RouterModule.forChild (ROUTES)

Was ist der Unterschied zwischen diesen beiden und was sind die Anwendungsfälle für jeden?

Die docs sind nicht gerade hilfreich:

forRoot erstellt ein Modul, das alle Anweisungen, die angegebenen Routen und den Routerdienst selbst enthält.

forChild erstellt ein Modul, das alle Anweisungen und die angegebenen Routen enthält, jedoch nicht den Routerdienst.

Meine vage Vermutung ist, dass eines für das 'Haupt'-Modul und das andere für alle importierten Module ist (da sie den Dienst bereits vom Hauptmodul zur Verfügung haben würden), aber ich kann mir keinen Anwendungsfall vorstellen.

78
VSO

Ich empfehle dringend, diesen Artikel zu lesen:

Modul mit Anbietern

Wenn Sie ein Modul importieren, verwenden Sie normalerweise einen Verweis auf die Modulklasse:

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

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

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

Auf diese Weise werden alle im Modul A registrierten Anbieter zum Root-Injektor hinzugefügt und stehen für die gesamte Anwendung zur Verfügung.

Es gibt aber auch eine andere Möglichkeit, ein Modul bei Anbietern wie diesem zu registrieren:

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

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

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

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

Dies hat die gleichen Auswirkungen wie das vorherige.

Sie wissen wahrscheinlich, dass faul geladene Module einen eigenen Injektor haben. Angenommen, Sie möchten AService registrieren, um für die gesamte Anwendung verfügbar zu sein, aber einige BService nur für verzögert geladene Module. Sie können Ihr Modul folgendermaßen umgestalten:

@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

Jetzt ist BService nur für untergeordnete faul geladene Module verfügbar, und AService ist für die gesamte Anwendung verfügbar.

Sie können das Obige wie folgt als exportiertes Modul umschreiben:

@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

Wie ist das für RouterModule relevant?

Angenommen, auf beide wird mit demselben Token zugegriffen:

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

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

Mit separaten Konfigurationen, wenn Sie token von einem faul geladenen Modul anfordern, erhalten Sie BService wie geplant.

RouterModule verwendet das Token ROUTES, um alle für ein Modul spezifischen Routen abzurufen. Da Routen für das verzögert geladene Modul in diesem Modul verfügbar sein sollen (analog zu unserem BService), werden für die verzögert geladenen untergeordneten Module unterschiedliche Konfigurationen verwendet:

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

In der Dokumentation ist der Zweck dieser Unterscheidung klar angegeben: https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root

Rufen Sie forRoot nur im Stammanwendungsmodul AppModule auf. Das Aufrufen in einem anderen Modul, insbesondere in einem verzögert geladenen Modul, widerspricht der Absicht und führt wahrscheinlich zu einem Laufzeitfehler.

Denken Sie daran, das Ergebnis zu importieren. Füge es keiner anderen @ NgModule-Liste hinzu.

Jede Anwendung hat genau einen Startpunkt (root), an dem der Hauptroutingdienst mit forRoot initialisiert werden soll, während Routen für bestimmte "untergeordnete" Features zusätzlich mit forChild registriert werden sollen. Es ist äußerst nützlich für Submodule und verzögert geladene Module, die beim Start der Anwendung nicht geladen werden müssen. Wie @Harry Ninh sagte, werden sie angewiesen, RouterService anstelle der Registrierung des neuen Dienstes erneut zu verwenden, was zu einem Laufzeitfehler führen kann.

24
Marcin

Ich denke, die Antworten sind richtig, aber ich denke, dass etwas fehlt.
Was fehlt, ist "warum und was es löst?".
In Ordnung, lass uns anfangen.

Lassen Sie uns zuerst einige Informationen erwähnen:

Alle Module haben Zugriff auf die Root-Dienste.
So können auch faul geladene Module einen Dienst nutzen, der in app.module bereitgestellt wurde.
Was passiert, wenn sich ein faul geladenes Modul einen Dienst zur Verfügung stellt, den das App-Modul bereits bereitgestellt hat? es wird 2 Instanzen geben.
Es ist kein Problem aber manchmal ist es.
Wie können wir das lösen? Importieren Sie einfach kein Modul mit diesem Anbieter in faul geladene Module.

Ende der Geschichte.

Dies soll nur zeigen, dass faul geladene Module einen eigenen Einspeisepunkt haben (im Gegensatz zu nicht faul geladenen Modulen).

Aber was passiert, wenn ein shared (!) Modul providers deklariert hat und dieses Modul von Lazy und app.module importiert wird? Wieder, wie gesagt, zwei Instanzen.

Wie können wir das im gemeinsam genutzten Modul POV lösen? wir brauchen einen Weg nicht um providers:[] zu benutzen! Warum ? Weil sie automatisch in die Modules "Consuming Lazy" und "App.Module" importiert werden und wir das nicht wollen, da wir gesehen haben, dass jedes Modul eine andere Instanz hat.

Nun, es stellt sich heraus, dass wir ein gemeinsam genutztes Modul deklarieren können, das nicht über providers:[] verfügt, aber dennoch Prodiver bereitstellt (sorry :))

Wie ? So was :

enter image description here

Hinweis, keine Anbieter.

Aber

  • was passiert jetzt, wenn app.module das gemeinsam genutzte Modul mit POV of Service importiert? NICHTS.

  • was passiert jetzt, wenn ein Lazy-Modul das gemeinsam genutzte Modul mit POV of Service importiert? NICHTS.

Manuellen Mechanismus über Konvention eingeben:

Sie werden feststellen, dass die Anbieter auf den Bildern service1 und service2 haben.

Dadurch können wir service2 für verzögert geladene Module und service1 für nicht verzögerte Module importieren. ( Husten ... Router .... Husten)

Übrigens hindert Sie niemand daran, forRoot innerhalb eines Lazy-Moduls aufzurufen. Sie werden aber 2 Instanzen haben, weil app.module es auch tun sollte - also nicht in Lazy-Modulen.

Auch - wenn app.moduleforRoot aufruft (und niemand forchild aufruft) - ist das in Ordnung, aber Root Injector wird nur service1 haben. (für alle Apps verfügbar)

Warum brauchen wir es also? Ich würde sagen :

Es ermöglicht einem gemeinsam genutzten Modul, seine verschiedenen Anbieter aufzuteilen , um mit eifrigen Modulen und faulen Modulen verwendet zu werden - über forRoot und forChild Konvention. Ich wiederhole: Konvention

Das war's.

WAIT !! kein einziges Wort über Singleton ?? Warum lese ich dann überall Singleton?

Nun - es ist im obigen Satz versteckt ^

Es ermöglicht einem gemeinsam genutzten Modul, seine verschiedenen Anbieter aufzuteilen , um mit eifrigen Modulen und faulen Modulen verwendet zu werden - über forRoot und forChild .

Die Konvention (!!!) erlaubt es, Singleton zu sein - oder genauer zu sein - wenn Sie die Konvention nicht befolgen - werden Sie [ ~ # ~] nicht [~ # ~] einen Singleton bekommen.
Wenn Sie also nur forRoot in den app.module laden, erhalten Sie nur eine Instanz, da Sie nur forRoot im app.module aufrufen sollten.
Übrigens: An dieser Stelle können Sie forChild vergessen. Das faul geladene Modul sollte/wird nicht forRoot aufrufen - Sie sind also in der POV von Singleton sicher.

forRoot und forChild sind kein unzerbrechliches Paket - es gibt nur keinen Grund, nach Root zu rufen, der offensichtlich nur in app.module geladen wird, ohne die Möglichkeit zu geben, Lazy-Module zu verwenden, eigene Dienste zu haben, ohne neue Dienste zu erstellen, die sollten. Be-Singleton.

Diese Konvention bietet Ihnen die Möglichkeit forChild, "Dienste nur für verzögert geladene Module" zu nutzen.

Hier ist eine Demo. Root-Provider liefern positive Zahlen, faul geladene Module negative Zahlen.

23
Royi Namir

Wenn appRoutes den Pfad zu verschiedenen Funktionen auf der Site enthält (admin crud, user crud, book crud) und wir sie trennen möchten, können wir dies einfach tun:

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

Und für Strecken:

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