#angular
#angular
Вопрос:
В основном вместо этого:
class Controller implements AfterViewInit{
@ViewChild(IconComponent)
iconComponent: IconComponent;
ngAfterViewInit() {
iconComponent.save();
}
}
Я хотел бы получить такой компонент:
class Controller implements AfterViewInit{
ngAfterViewInit() {
const iconComponent = someRef.get(IconComponent); // where to get this component from
iconComponent.save()
}
}
Как мне этого добиться?
Я задаю этот вопрос, потому что я получаю тип компонента во время выполнения, а не во время компиляции.
Комментарии:
1. ViewChild может использовать другой селектор, а не компонент или класс. используйте ссылку на переменную «дочерний» и
ViewChild('child',{read:BaseClass}) myBaseComponent
2. В аннотации вы должны знать тип компонента во время компиляции. Я не знаю его тип там, поэтому мне нужно решение, которое позволяет мне использовать динамический тип среды выполнения
3. Если ваш компонент реализует интерфейс (имеет общие функции и свойства, я думаю, но я не уверен, что вы можете использовать этот интерфейс)
4. @Humberd Как компоненты используются в шаблоне? Например, помещаются ли они внутри тегов контроллера
<controller> <IconComp><IconComp></controller>
. Можно ли убедиться, что компоненты имеют ссылку на шаблон, размещенную на них, например#target
?
Ответ №1:
Почему бы вам не создать компонент с предоставленным ComponentFactoryResolver
?
Таким образом, вы можете получить его ComponentRef и управлять его экземпляром.
Вот документация ComponentFactoryResolver, и вы можете найти там хороший пример реализации.
Комментарии:
1. Ну, из-за этого я не хочу вручную создавать много компонентов. Я не хочу повторять @ViewChild, а затем вызывать те же методы в этих компонентах. Мои компоненты будут наследоваться от базового класса, который будет получать эти компоненты и выполнять грязные вещи. Базовый класс не должен создавать компоненты, потому что он не знает, куда их поместить.
2. Я вижу, может быть, вы можете ввести
ApplicationRef
, а затем получить доступ к его свойствуcomponents
, где вы найдете все зарегистрированные компоненты в приложении. Не решайте полностью вашу проблему…3. Еще одна проблема с динамически созданными компонентами заключается в том, что горячая перезагрузка модуля не перезагружает их. Это просто оставляет их зависшими.
4.
ApplicationRef
тоже не помогает. Мне пришлось бы копаться в огромной куче компонентов, и было бы проблематично найти именно тот компонент, который я ищу.
Ответ №2:
У вас может быть токен инъекции. Даже если типы приведут к ошибкам (следовательно, приведение к любому), это сработает:
@ViewChild(YOUR_TOKEN as any)
component: YourAbstractClass;
Или, если вы пометили их все с помощью какой-либо ссылочной переменной шаблона:
@ViewChild('some', {read: YOUR_TOKEN})
component: YourAbstractClass;
Все компоненты, производные от вашего абстрактного класса, должны предоставлять этот токен:
@Component({
selector: 'your-component',
templateUrl: './yourComponent.template.html',
styleUrls: ['./yourComponent.style.less'],
providers: [
{
provide: YOUR_TOKEN,
useExisting: forwardRef(() => YourComponent ),
},
],
})
export class YourComponent extends YourAbstractClass {
Таким образом, вы также можете ввести их все в директивы.
Комментарии:
1. Ваше решение требует знания типа во время компиляции. Я не знаю такого типа людей. Тип передается, например, как аргумент функции.
2. Можете ли вы рассказать нам несколько примеров
dirty stuff
того, что должен был бы сделать ваш базовый класс? Вы можете пометить эти компоненты ссылочной переменной шаблона и сделать свой базовый класс универсальным, а затем дочерние классы присвоят ему тип. Однако я не уверен, что вы можете сделать с универсальным в базовом классе. Вам нужно будет, по крайней мере, указать возможные интерфейсы. Пожалуйста, приведите конкретные примеры, я уверен, мы сможем что-нибудь придумать.3. @pokrishka Это умный подход. Это очень похоже на то, как угловые реактивные формы работают под капотом. Они добавляются
multi: true
к поставщику, и все компоненты directive / custom затем добавляются в этот массив поставщиков