Injeksi Ketergantungan Sudut Dijelaskan dengan Contoh

Apa itu Injeksi Ketergantungan?

Motivasi

Dependency Injection sering lebih sederhana disebut sebagai DI. Paradigma itu ada di seluruh Angular. Itu membuat kode tetap fleksibel, dapat diuji, dan berubah. Kelas dapat mewarisi logika eksternal tanpa mengetahui cara membuatnya. Setiap konsumen dari kelas tersebut juga tidak perlu tahu apa-apa.

DI menyelamatkan kelas dan konsumen dari keharusan untuk mengetahui lebih dari yang diperlukan. Namun kodenya sama modularnya dengan sebelumnya berkat mekanisme yang mendukung DI di Angular.

Layanan adalah dermawan utama DI. Mereka mengandalkan paradigma injeksi ke berbagai konsumen. Konsumen tersebut kemudian dapat memanfaatkan layanan yang diberikan dan / atau meneruskannya ke tempat lain.

Pelayanan tidak sendiri. Direktif, pipa, komponen, dan sebagainya: setiap skema di Angular mendapat manfaat dari DI dalam beberapa cara atau lainnya.

Injector

Injector adalah struktur data yang menyimpan instruksi yang merinci di mana dan bagaimana bentuk layanan. Mereka bertindak sebagai perantara dalam sistem Angular DI.

Modul, direktif, dan kelas komponen berisi metadata khusus untuk injektor. Contoh injektor baru menyertai setiap kelas ini. Dengan cara ini, pohon aplikasi mencerminkan hierarki injektornya.

The providers: []metadata menerima layanan yang kemudian mendaftar dengan injektor kelas. Bidang penyedia ini menambahkan instruksi yang diperlukan agar injektor berfungsi. Sebuah kelas (dengan asumsi ia memiliki ketergantungan) membuat instance layanan dengan menggunakan kelasnya sebagai tipe datanya. Injector menyelaraskan tipe ini a membuat instance dari layanan itu atas nama kelas.

Tentu saja, kelas hanya dapat memberi contoh untuk apa injektor memiliki instruksi. Jika injektor milik kelas tidak memiliki layanan yang terdaftar, maka ia akan menanyakan induknya. Begitu seterusnya hingga mencapai injektor dengan layanan atau aplikasi root.

Layanan dapat mendaftar di sembarang injektor dalam aplikasi. Layanan masuk ke providers: []bidang metadata modul kelas, arahan, atau komponen. Anak-anak kelas dapat membuat contoh layanan yang terdaftar di injektor kelas. Injector anak kembali ke injektor induk.

Injeksi Ketergantungan

Lihatlah kerangka untuk setiap kelas: layanan, modul, direktif, dan komponen.

// service import { Injectable } from '@angular/core'; @Injectable({ providedIn: /* injector goes here */ }) export class TemplateService { constructor() { } }
// module import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [], providers: [ /* services go here */ ] }) export class TemplateModule { }
// directive import { Directive } from '@angular/core'; @Directive({ selector: '[appTemplate]', providers: [ /* services go here */ ] }) export class TemplateDirective { constructor() { } }
//component import { Component } from '@angular/core'; @Component({ selector: 'app-template', templateUrl: './template.component.html', styleUrls: ['./template.component.css'], providers: [ /* services go here */ ] }) export class TemplateComponent { // class logic ... }

Setiap kerangka dapat mendaftarkan layanan ke injektor. Sebenarnya, TemplateService adalah sebuah layanan. Mulai Angular 6, layanan sekarang dapat mendaftar dengan injektor menggunakan @Injectablemetadata.

Dalam Kasus Apa Pun

Perhatikan metadata providedIn: string( @Injectable) dan providers: []( @Directive, @Componetdan @Module). Mereka memberi tahu injektor di mana dan bagaimana membuat layanan. Jika tidak, injektor tidak akan tahu cara membuat instance.

Bagaimana jika layanan memiliki ketergantungan? Kemana hasilnya? Penyedia menjawab pertanyaan tersebut sehingga injektor dapat memberi contoh dengan benar.

Injector membentuk tulang punggung kerangka DI. Mereka menyimpan instruksi untuk memberi contoh layanan sehingga konsumen tidak perlu melakukannya. Mereka menerima contoh layanan tanpa perlu tahu apa-apa tentang ketergantungan sumber!

Saya juga harus mencatat bahwa skema lain tanpa injektor masih dapat menggunakan injeksi ketergantungan. Mereka tidak dapat mendaftarkan layanan tambahan tetapi mereka masih dapat membuat contoh dari injektor.

Layanan

The providedIn: stringmetadata dari @Injectablemenentukan yang injektor untuk mendaftar dengan. Menggunakan metode ini, dan bergantung pada apakah layanan digunakan, layanan mungkin atau mungkin tidak terdaftar dengan injektor. Angular menyebut ini gemetar pohon .

Secara default, nilai ditetapkan ke ‘root’. Ini diterjemahkan ke injektor root aplikasi. Pada dasarnya, menyetel bidang agar ‘root’layanan tersedia di mana saja.

Catatan Cepat

Seperti yang disebutkan sebelumnya, injektor anak bergantung pada orang tua mereka. Strategi fallback ini memastikan orang tua tidak perlu mendaftar ulang untuk setiap injector. Lihat artikel ini di Layanan dan Injektor untuk ilustrasi konsep ini.

Layanan terdaftar adalah lajang . Artinya, instruksi untuk membuat instance layanan hanya ada pada satu injektor. Ini mengasumsikan itu belum terdaftar secara eksplisit di tempat lain.

Modul, Petunjuk, dan Komponen

Modul dan komponen masing-masing memiliki contoh injektor sendiri. Ini terbukti mengingat providers: []bidang metadata. Bidang ini mengambil berbagai layanan dan mendaftarkannya dengan injektor modul atau kelas komponen. Pendekatan ini terjadi di @NgModule, @Directive, atau @Componentdekorator.

Strategi ini menghilangkan goyangan pohon , atau penghapusan opsional layanan yang tidak digunakan dari injektor. Instans layanan aktif di injektornya selama masa pakai modul atau komponen.

Referensi Instansiasi

Referensi ke DOM dapat dibuat dari kelas mana pun. Perlu diingat bahwa referensi tetaplah layanan. Mereka berbeda dari layanan tradisional dalam merepresentasikan keadaan sesuatu yang lain. Layanan ini mencakup fungsi untuk berinteraksi dengan referensi mereka.

Direktif selalu membutuhkan referensi DOM. Direktif melakukan mutasi pada elemen inangnya melalui referensi ini. Lihat contoh berikut. Injector direktif memberi contoh referensi elemen host ke konstruktor kelas.

// directives/highlight.directive.ts import { Directive, ElementRef, Renderer2, Input } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { constructor( private renderer: Renderer2, private host: ElementRef ) { } @Input() set appHighlight (color: string) { this.renderer.setStyle(this.host.nativeElement, 'background-color', color); } }
// app.component.html 

Highlighted Text!

Renderer2juga dipakai. Dari injektor mana layanan ini berasal? Nah, setiap kode sumber layanan berasal @angular/core. Layanan ini kemudian harus terdaftar dengan injektor akar aplikasi.

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { HighlightDirective } from './directives/highlight.directive'; @NgModule({ declarations: [ AppComponent, HighlightDirective ], imports: [ BrowserModule ], providers: [], bootstrap: [ AppComponent ] }) export class AppModule { }

Array penyedia kosong !? Bukan untuk takut. Angular mendaftarkan banyak layanan dengan injektor root secara otomatis. Ini termasuk ElementRefdan Renderer2. Dalam contoh ini, kami mengelola elemen host melalui antarmuka yang berasal dari pembuatan instance ElementRef. Renderer2mari kita perbarui DOM melalui model tampilan Angular.

You can read more about views from this article. They are the preferred method for DOM/view updates in Angular applications.

It is important recognize the role that injectors play in the above example. By declaring variable types in the constructor, the class obtains valuable services. Each parameter’s data type maps to a set of instructions within the injector. If the injector has that type, it returns an instance of said type.

Instantiating Services

The Services and Injectors article explains this section to an extent. Though, this section rehashes the previous section or the most part. Services will often provide references to something else. They may just as well provide an interface extending a class’ capabilities.

The next example will define a logging service that gets added to a component’s injector via its providers: [] metadata.

// services/logger.service.ts import { Injectable } from '@angular/core'; @Injectable() export class LoggerService { callStack: string[] = []; addLog(message: string): void { this.callStack = [message].concat(this.callStack); this.printHead(); } clear(): void { this.printLog(); this.callStack = []; console.log(“DELETED LOG”); } private printHead(): void  null);  private printLog(): void { this.callStack.reverse().forEach((log) => console.log(message)); } }
// app.component.ts import { Component } from '@angular/core'; import { LoggerService } from './services/logger.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', providers: [LoggerService] }) export class AppComponent { constructor(private logger: LoggerService) { } logMessage(event: any, message: string): void { event.preventDefault(); this.logger.addLog(`Message: ${message}`); } clearLog(): void { this.logger.clear(); } }
// app.component.html 

Log Example

SUBMIT

Delete Logged Messages

CLEAR

Focus on the AppComponent constructor and metadata. The component injector receives instructions from the provider’s metadata field containing LoggerService. The injector then knows what to instantiate LoggerService from requested in the constructor.

The constructor parameter loggerService has the type LoggerService which the injector recognizes. The injector follows through with the instantiation as mentioned.

Conclusion

Dependency injection (DI) is a paradigm. The way it works in Angular is through a hierarchy of injectors. A class receives its resources without having to create or know about them. Injectors receive instruction and instantiate a service depending on which one was requested.

DI shows up a lot in Angular. The official Angular documentation explains why the paradigm is so prevalent. They also go on to describe the numerous use-cases for DI in Angular way beyond what was discussed in this article. Check it out by clicking below!

More on dependency injection:

  • Intro to Angular dependency injection
  • Quick intro to dependency injection