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