Как я могу определить поставщика с возможностью разделения на деревья для конкретной реализации на уровне приложения для интерфейса уровня библиотеки в Angular 6+? - PullRequest
0 голосов
/ 11 марта 2020

Мы используем 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? Пожалуйста, имейте в виду отделение библиотеки от прикладных проектов.

...