Мы используем Angular 7 в настоящее время. Я прочитал руководство Angular по внедрению зависимостей и созданию провайдеров с возможностью ветвления дерева. Я прочитал дюжину вопросов и ответов и постов в блоге об определении InjectionTokens или об использовании абстрактных классов в качестве токенов для предоставления конкретного класса для интерфейса или абстрактного класса. Но все они, похоже, предполагают, что весь код находится в одном проекте Angular.
В нашей архитектуре у меня есть проект библиотеки Angular, который содержит мой интерфейс и InjectionToken:
export const MY_SERVICE = new InjectionToken<MyService>('my-service');
export interface MyService {
someMethod();
}
В этом проекте библиотеки у меня есть директива, которая вводит этот токен:
export class MyDirective {
constructor(@Inject(MY_SERVICE) myService: MyService) { }
@HostListener('click')
private clicked() {
this.myService.someMethod();
}
}
Я хочу предоставить фактическую реализацию для этой службы на уровне приложения, который является другим Angular проектом который импортирует проект библиотеки.
Проект приложения Angular будет иметь конкретную реализацию MyService:
@Injectable({
providedIn: 'root'
})
export class ConcreteMyService implements MyService {
someMethod() {
console.log('Application specific concrete implementation!');
}
}
Я использую providedIn: 'root'
, потому что все, что я прочитал, говорит, что это требуется сделать это дерево шатким. Проблема в том, что я не вижу, как подключить эту систему к DI-системе Angular, чтобы ConcreteMyService
можно было впрыскивать в MyDirective
, оставаясь при этом доступным для дерева.
Имейте в виду что MyDirective
и MyService
находятся в проекте, отличном от ConcreteMyService
, и не знают об этом. Это сделано специально и не должно меняться.
Я упоминаю об этом, потому что я видел, как другие предлагали сделать следующее при настройке InjectionToken:
export const MY_SERVICE = new InjectionToken<MyService>('my-service', {
factory: () => new ConcreteMyService()
});
Проблема в том, что ConcreteMyService
недоступно в проекте библиотеки, и не должно быть ... это не вариант.
Единственное решение, которое я видел, похоже, достигло sh того, что я Я хотел бы добавить провайдера к модулю, например:
@NgModule({
providers: [
{ provide: MY_SERVICE, useClass: ConcreteMyService }
]
})
export class SomeModule { }
Но это не так уж и сложно, как я понимаю, исходя из всего, что я прочитал.
Как я могу сделать ConcreteMyService
древо-шейкбэком, одновременно предоставляя его системе Angular DI для использования в случаях, когда запрашивается мой токен MY_SERVICE
? Пожалуйста, имейте в виду отделение библиотеки от прикладных проектов.