Dependency Injection trong angular - Bài 3 - Provider

Photo by Erik Mclean on Unsplash

Dependency Injection trong angular - Bài 3 - Provider

·

3 min read

Provider có tác dụng báo cho injector biết làm sao để tạo injector. Có 4 cách tạo provider useClass, useValue, useFactory, useExisting.

vd: providers :[{ provide: ProductService, useClass: ProductService }]

Thuộc tính provide: chính là token, injector dựa vào token này để xác định provider, giá trị của nó có thể là Token Type, string token hoặc 1 instance Injection Token.

(Như trường hợp trên - ProductService là 1 type token, string token là 1 string, Injection Token được tạo ra bằng cách dùng new InjectionToken(''); )

Thuộc tính useClass(hoặc useValue, useFactory, useExisting): chính là provider, nó hướng dẫn cho injector cách để tạo ra dependency.

Sự khác nhau cơ bản ở 4 cách tạo trên là useClass tạo dependency từ service class, với useValue thì nó là 1 value, array, object ..., với usefactory thì nó sẽ trả về 1 instance của factory function, với useExisting nó sẽ trả về 1 instance từ 1 token đã tồn tại. Sau đây sẽ đi vào chi tiết.

1. useClass

Khi dùng useClass, cần phải cung cấp 1 type cho nó, dưới đây là ProductService providers :[{ provide: ProductService, useClass: ProductService }] vì token và provider giống nhau nên có thể viết gọn lại thành providers :[ProductService]

dựa vào type là ProductService, injector sẽ tạo 1 instance, nếu đã tồn tại 1 instance từ trước(instance trong scope của nó) , nó sẽ không tạo mới mà lấy luôn và inject vào constructor.

vd2: providers :[{ provide: ProductService, useClass: fakeProductService }] Với vd này, khi muốn inject ProductService vào, injector sẽ lấy 1 instance của fakeProductService.

2. useValue

Khi sử dụng useValue, injector sẽ lấy chính giá trị của nó để inject vào providers :[ {provide:'USE_FAKE', useValue: true}] Khi inject vào cần dùng @Inject

export class AppComponent { constructor( @Inject('USE_FAKE') public useFake: boolean ) {}

=> giá trị của useFake = true với useValue có thể đưa bất kì giá trị nào vào

VD: đưa 1 function vào providers: [ { provide: 'FUNC', useValue: () => { return 'hello'; } } ]

export class AppComponent { constructor( @Inject('FUNC') public someFunc: any ) { console.log(someFunc()); } }

Lưu ý : với TH trên someFunc sẽ là 1 function, do đó cần phải trigger nó mới chạy, khác với useFactory dưới đây.

3.useFactory

useFactory yêu cầu truyền vào 1 function và nó sẽ tự động trigger để trả về 1 instance, khác với useValue là nó sẽ trả về chính function truyền vào, còn usefactory sẽ tự động thực thi function và trả về instance

providers: [ { provide: LoggerService, useClass: LoggerService },

{ provide: 'USE_FAKE', useValue: true },

{
  provide: ProductService,
  useFactory: (USE_FAKE, LoggerService) =>
    USE_FAKE ? new FakeProductService() : new ProductService(LoggerService),
  deps: ['USE_FAKE', LoggerService]
}

]

Ta thấy useFactory sử dụng 2 tham số, 2 tham số này là 2 dependency, dựa vào giá trị của USE_FAKE, useFactory sẽ trả về FakeProductService hoặc ProductService, usefactory cần báo cho injector biết nó đang có 2 dependency khác là 'USE_FAKE', LoggerService, vì thế ta thêm vào deps để injector inject 2 dependency này vào cho method của useFactory, nhớ đặt đúng vị trí trong deps với vị trí các tham số này trong method của useFactory.

4.useExisting

Khi muốn sử dụng 1 service khác, ta có thể dùng useExisting providers: [{ provide: ProductService, useExisting: NewProductService }] => khi có dependency là ProductService, nó sẽ được thay thế bằng NewProductService