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

111

Apa perbedaan antara keduanya dan apa kasus penggunaan untuk masing-masing?

The docs tidak persis membantu:

forRoot membuat modul yang berisi semua arahan, rute yang diberikan, dan layanan router itu sendiri.

forChild membuat modul yang berisi semua arahan dan rute yang diberikan, tetapi tidak menyertakan layanan router.

Dugaan samar saya adalah bahwa satu untuk modul 'utama' dan yang lainnya untuk modul yang diimpor (karena mereka sudah memiliki layanan yang tersedia dari modul utama), tetapi saya tidak dapat benar-benar memikirkan kasus penggunaan.

VSO
sumber
1
Bisakah Anda lebih spesifik tentang apa yang tidak Anda pahami? Kutipan yang Anda sertakan secara harfiah memberi tahu Anda apa perbedaannya.
jonrsharpe
2
Saya tidak mengerti apa gunanya menggunakan .forChild (). Kapan saya menginginkan arahan dan rute tanpa layanan? Sementara itu, harap jawab pertanyaan yang Anda hapus dari postingan ...
VSO
18
Seharusnya hanya ada satu RouterServiceuntuk satu aplikasi Angular2. forRootakan menginisialisasi layanan itu dan mendaftarkannya ke DI bersama dengan beberapa konfigurasi rute, sementara forChildhanya akan mendaftarkan konfigurasi rute tambahan dan memberi tahu Angular2 untuk menggunakan kembali RouterServiceyang forRoottelah dibuat.
Harry Ninh
@HarryNinh: Terima kasih - itulah yang saya cari. Kapan Anda ingin mendaftarkan rute tambahan di luar pendaftaran awal? Sepertinya konyol. Saya menduga tidak ada cara untuk membuat rute secara dinamis.
VSO
1
lihat ini oleh penulis router sudut victor.
nikhil mehta

Jawaban:

123

Saya sangat menyarankan membaca artikel ini:

Modul dengan penyedia

Saat Anda mengimpor modul, Anda biasanya menggunakan referensi ke kelas modul:

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

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

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

Dengan cara ini semua penyedia yang terdaftar di modul Aakan ditambahkan ke injektor akar dan tersedia untuk seluruh aplikasi.

Tetapi ada cara lain untuk mendaftarkan modul dengan penyedia seperti ini:

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

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

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

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

Ini memiliki implikasi yang sama dengan yang sebelumnya.

Anda mungkin tahu bahwa modul yang dimuat lambat memiliki injektor sendiri. Jadi misalkan Anda ingin mendaftar AServiceagar tersedia untuk seluruh aplikasi, tetapi beberapa BServicehanya tersedia untuk modul yang dimuat lambat. Anda dapat memfaktorkan ulang modul Anda seperti ini:

@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

Sekarang BServicehanya akan tersedia untuk modul pemuatan lambat anak dan AServiceakan tersedia untuk seluruh aplikasi.

Anda dapat menulis ulang di atas sebagai modul yang diekspor seperti ini:

@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

Bagaimana itu relevan dengan RouterModule?

Misalkan keduanya diakses menggunakan token yang sama:

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

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

Dengan konfigurasi terpisah ketika Anda meminta tokendari modul yang dimuat lambat, Anda akan mendapatkan BServiceseperti yang direncanakan.

RouterModule menggunakan ROUTEStoken untuk mendapatkan semua rute khusus untuk sebuah modul. Karena ingin rute khusus untuk modul yang dimuat lambat tersedia di dalam modul ini (analog dengan BService kami), ia menggunakan konfigurasi berbeda untuk modul turunan yang dimuat lambat:

static forChild(routes: Routes): ModuleWithProviders {
    return {
        ngModule: RouterModule, 
        providers: [{provide: ROUTES, multi: true, useValue: routes}]
    };
}
Max Koretskyi
sumber
3
jadi dengan kata lain, kita harus memanggil forChild () dalam modul fitur karena forRoot () sudah dipanggil dalam modul root dan semua layanan yang diperlukan telah ditambahkan. Jadi memanggil forRoot () lagi akan menyebabkan status yang tidak dapat diprediksi?
Wachburn
7
@Wachburn, memanggil forRootmodul yang dimuat lambat akan membuat instance baru dari semua layanan global di injektor modul yang dimuat lambat. Ya, ini akan memberikan hasil yang tidak terduga. Baca juga artikel ini Menghindari kebingungan umum dengan modul di Angular
Max Koretskyi
1
@Willwarp, kenapa?
Max Koretskyi
1
Saya sangat memahami ini. Tapi Apa perbedaan antara Routermodule.foRoot, VS Routermodule.forChild? forRoot & forChild hanyalah metode statis yang memberikan objek sebagai imbalan berdasarkan nilai yang diteruskan. Jadi dalam modul aplikasi, mengapa saya tidak dapat menggunakan forChild ?? mengapa kesalahan lemparannya? Mengapa saya tidak dapat menggunakan beberapa forRoot?
Subhadeep
2
Kadang-kadang, itu baik untuk langsung ke pokok permasalahan dengan jawaban. informasi yang berlebihan sering kali menyebabkan lebih banyak kebingungan.
Adépòjù Olúwáségun
33

Saya pikir jawabannya benar tetapi saya pikir ada sesuatu yang hilang.
Hal yang kurang adalah "mengapa dan apa yang dipecahkannya?".
Ok mari kita mulai.

Pertama mari kita sebutkan beberapa info:

Semua modul memiliki akses ke layanan root.
Jadi, bahkan modul yang dimuat lambat dapat menggunakan layanan yang disediakan di app.module.
Apa yang akan terjadi jika modul yang dimuat lambat akan menyediakan layanan yang telah disediakan oleh modul aplikasi itu sendiri? akan ada 2 contoh.
Itu bukan masalah tapi terkadang memang begitu .
Bagaimana kita bisa mengatasinya? cukup jangan mengimpor modul dengan penyedia tersebut ke modul yang dimuat lambat.

Akhir dari cerita.

^ Ini hanya untuk menunjukkan bahwa modul yang dimuat lambat memiliki titik injeksi mereka sendiri (berbeda dengan modul yang tidak dimuat dengan lambat).

Tetapi apa yang terjadi ketika modul bersama (!) Telah dideklarasikan providers, dan modul itu diimpor oleh lazy dan app.module ? Sekali lagi, seperti yang kami katakan, dua contoh.

Jadi bagaimana kita bisa menyelesaikan ini di modul POV bersama? Kami membutuhkan cara untuk tidak menggunakan providers:[]! Mengapa? karena keduanya akan diimpor secara otomatis ke penggunaan lazy dan app.module dan kami tidak menginginkannya karena kami melihat bahwa masing-masing akan memiliki instance yang berbeda.

Nah, ternyata kita dapat mendeklarasikan modul bersama yang tidak akan dimiliki providers:[], tetapi tetap akan menyediakan penyedia (maaf :))

Bagaimana? Seperti ini :

masukkan deskripsi gambar di sini

Perhatikan, tidak ada penyedia.

Tapi

  • apa yang akan terjadi sekarang ketika app.module akan mengimpor modul bersama dengan POV layanan? TIDAK ADA.

  • apa yang akan terjadi sekarang ketika modul malas akan mengimpor modul bersama dengan POV layanan? TIDAK ADA.

Memasuki mekanisme Manual melalui konvensi:

Anda akan melihat bahwa penyedia di gambar memiliki service1danservice2

Ini memungkinkan kita untuk mengimpor service2modul yang dimuat lambat dan service1untuk modul non-malas. ( batuk ... router .... batuk )

BTW, tidak ada yang menghentikan Anda untuk menelepon forRootdalam modul malas. tetapi Anda akan memiliki 2 instance karena app.moduleharus melakukannya - jadi jangan lakukan itu di modul lazy.

Juga - jika app.modulepanggilan forRoot(dan tidak ada yang memanggil forchild) - tidak apa-apa, tetapi injektor akar hanya akan melakukannya service1. (tersedia untuk semua aplikasi)

Jadi mengapa kita membutuhkannya? Aku akan mengatakan :

Ini memungkinkan modul bersama, untuk dapat membagi penyedia berbeda untuk digunakan dengan modul eager dan modul malas - melalui forRootdan forChildkonvensi. Saya ulangi: konvensi

Itu dia.

TUNGGU !! tidak ada satu kata pun tentang singleton ?? jadi mengapa saya membaca tunggal di mana-mana?

Nah - itu tersembunyi dalam kalimat di atas ^

Ini memungkinkan modul bersama, untuk dapat membagi penyedia yang berbeda untuk digunakan dengan modul eager dan modul malas - melalui forRoot dan forChild .

The konvensi (!!!) memungkinkan untuk menjadi tunggal - atau lebih tepatnya - jika Anda tidak akan mengikuti konvensi - Anda akan tidak mendapatkan tunggal.
Jadi jika Anda hanya memuat forRootdi app.module , maka Anda hanya mendapatkan satu contoh karena Anda hanya harus memanggilnya forRootdi app.module.
BTW - pada titik ini Anda bisa melupakan forChild. modul yang dimuat malas seharusnya / tidak akan memanggil forRoot- jadi Anda aman di POV tunggal.

forRoot dan forChild bukanlah satu paket yang tidak dapat dipecahkan - hanya saja tidak ada gunanya memanggil Root yang jelas hanya akan dimuat app.module tanpa memberikan kemampuan untuk modul malas, memiliki layanan sendiri, tanpa membuat layanan baru-yang-seharusnya-ada. -singleton.

Konvensi ini memberi Anda kemampuan bagus yang dipanggil forChild- untuk menggunakan "layanan hanya untuk modul yang dimuat lambat".

Berikut ini demo Penyedia root menghasilkan angka positif, modul yang dimuat lambat menghasilkan angka negatif.

Royi Namir
sumber
1. Apa POV di sini? 2. stackblitz tidak berfungsi lagi.
Nicholas K
@NicholasK stackblitz ini selalu mengacaukan banyak hal setelah beberapa saat. saya akan mencoba mengunggah versi baru
Royi Namir
26

Dokumentasi dengan jelas menyatakan apa tujuan dari perbedaan ini di sini: https://angular.io/docs/ts/latest/guide/ngmodule.html#!#core-for-root

Panggil forRoot hanya di modul aplikasi root, AppModule. Memanggilnya di modul lain, terutama dalam modul yang dimuat lambat, bertentangan dengan maksudnya dan kemungkinan akan menghasilkan error waktu proses.

Ingatlah untuk mengimpor hasilnya; jangan menambahkannya ke daftar @NgModule lainnya.

Setiap aplikasi memiliki tepat satu titik awal (root) tempat layanan perutean utama harus diinisialisasi forRoot, sedangkan rute untuk fitur "turunan" tertentu harus didaftarkan sebagai tambahan forChild. Ini sangat berguna untuk submodul dan modul yang dimuat lambat yang tidak harus dimuat saat aplikasi dimulai, dan seperti yang dikatakan @Harry Ninh, mereka diberitahu untuk menggunakan kembali RouterService alih-alih pendaftaran layanan baru, yang dapat menyebabkan kesalahan waktu proses.

Marcin
sumber
2
Dokumen-dokumen itu tampaknya dipindahkan, v2.angular.io/docs/ts/latest/guide/…
PeterS
1

Jika appRoutes berisi jalur ke berbagai fungsi di situs (admin crud, user crud, book crud) dan kami ingin memisahkannya, kami dapat melakukannya:

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

Dan untuk rute:

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},



]
Hmaied Belkhiria
sumber