У меня есть набор компонентов angular2, в которые должны быть внедрены некоторые службы. Моя первая мысль заключалась в том, что было бы лучше создать суперкласс и внедрить туда сервис. Тогда любой из моих компонентов расширил бы этот суперкласс, но этот подход не работает.
Упрощенный пример:
export class AbstractComponent {
constructor(private myservice: MyService) {
// Inject the service I need for all components
}
}
export MyComponent extends AbstractComponent {
constructor(private anotherService: AnotherService) {
super(); // This gives an error as super constructor needs an argument
}
}
Я мог бы решить эту проблему, вводя MyService
в каждый компонент и используя этот аргумент для super()
вызова, но это определенно какой-то абсурд.
Как правильно организовать мои компоненты, чтобы они унаследовали сервис от суперкласса?
new MyService()
вместо инъекции дает вам точно такой же результат (за исключением более эффективного). Если вы хотите использовать один и тот же экземпляр службы для разных служб и / или компонентов, это не сработает. Каждый класс получит другойMyService
экземпляр.myService
. Нашел решение, которое позволяет избежать этого, но добавляет больше кода в производные классы ...Ответы:
Это не абсурд. Так работают конструкторы и внедрение конструкторов.
Каждый внедряемый класс должен объявлять зависимости как параметры конструктора, и если суперкласс также имеет зависимости, они также должны быть перечислены в конструкторе подкласса и переданы суперклассу с
super(dep1, dep2)
вызовом.Передача инжектора и получение зависимостей обязательно имеет серьезные недостатки.
Он скрывает зависимости, что затрудняет чтение кода.
Это нарушает ожидания человека, знакомого с тем, как работает Angular2 DI.
Он прерывает автономную компиляцию, которая генерирует статический код для замены декларативного и императивного DI для повышения производительности и уменьшения размера кода.
источник
super
вызовы) примерно к 20+ классам, и это число будет только расти в будущем. Итак, две вещи: 1) я бы не хотел, чтобы «большая кодовая база» сделала это; и 2) Слава Богу за vimq
и vscodectrl+.
Обновленное решение предотвращает создание нескольких экземпляров myService с помощью глобального инжектора.
Это гарантирует, что MyService может использоваться в любом классе, расширяющем AbstractComponent, без необходимости вводить MyService в каждый производный класс.
У этого решения есть некоторые минусы (см. Ccomment от @ Günter Zöchbauer ниже моего исходного вопроса):
Для очень хорошо написанного объяснения внедрения зависимостей в Angular2 см. Это сообщение в блоге, которое очень помогло мне решить проблему: http://blog.oughttram.io/angular/2015/05/18/dependency-injection-in-angular- 2.html
источник
this.myServiceA = injector.get(MyServiceA);
т. Д.?Injector
глобальное расширение, чтобы не связывать какие-либо параметрыAbstractComponent
? fwiw, я думаю, что свойство, вводящее зависимости в широко используемый базовый класс, чтобы избежать беспорядочного связывания конструкторов, является совершенно допустимым исключением из обычного правила.Вместо того, чтобы вводить все сервисы вручную, я создал класс, предоставляющий сервисы, например, он вводит сервисы. Затем этот класс вводится в производные классы и передается базовому классу.
Производный класс:
Базовый класс:
Класс предоставления услуг:
источник
Вместо того, чтобы внедрять сервис, который имеет все остальные сервисы в качестве зависимостей, например:
Я бы пропустил этот дополнительный шаг и просто добавил бы все службы в BaseComponent, например:
Этот метод предполагает 2 вещи:
Ваше беспокойство полностью связано с наследованием компонентов. Скорее всего, вы столкнулись с этим вопросом потому, что огромное количество несухого (WET?) Кода нужно повторять в каждом производном классе. Если вы хотите использовать единую точку входа для всех ваших компонентов и сервисов , вам нужно будет сделать дополнительный шаг.
Каждый компонент расширяет
BaseComponent
Также имеется недостаток, если вы решите использовать конструктор производного класса, так как вам нужно будет вызвать
super()
и передать все зависимости. Хотя я действительно не вижу варианта использования, который требовал бы использованияconstructor
вместоngOnInit
, вполне возможно, что такой вариант использования существует.источник
Насколько я понимаю, чтобы унаследовать от базового класса, вам сначала нужно создать его экземпляр. Чтобы создать его экземпляр, вам необходимо передать необходимые параметры его конструктору, таким образом, вы передаете их от дочернего элемента к родительскому через вызов super (), так что это имеет смысл. Инжектор, конечно, еще одно жизнеспособное решение.
источник
Если родительский класс был получен из стороннего плагина (и вы не можете изменить источник), вы можете сделать это:
или лучший способ (оставьте только один параметр в конструкторе):
источник
Уродливый взлом
Некоторое время назад некоторые из моих клиентов хотят присоединиться к двум БОЛЬШИМ проектам angular ко вчерашнему дню (angular v4 в angular v8). Project v4 использует класс BaseView для каждого компонента и содержит
tr(key)
метод перевода (в v8 я использую ng-translate). Поэтому, чтобы избежать переключения системы переводов и редактирования сотен шаблонов (в v4) или настройки двух систем перевода параллельно, я использую следующий уродливый хак (я не горжусь этим) - вAppModule
классе я добавляю следующий конструктор:и теперь
AbstractComponent
вы можете использоватьисточник