Прежде всего, в Angular> = 2.x больше нет области видимости. Контекст выполнения для шаблона компонента всегда является его классом компонента. Однако существует несколько способов связи между parent => child
и child => parent
.
Первый подход заключается в использовании декоратора @ContentChildren
, который вернет QueryList
. Это требует, чтобы вы либо добавили ссылочные переменные шаблона, например #myChild
. Вот так будет выглядеть ваш шаблон:
<component-smart1>
<component-dumb-1 #myDumbChild></component-dumb-1>
<component-dumb-2 #myDumbChild></component-dumb-2>
</component-smart1>
Используя декоратор @ContentChildren
, вы можете запрашивать эти ссылочные переменные и получать доступ к общедоступным API тупых компонентов.
Другой способ - использовать возможности системы DI. Например, вы можете настроить провайдера на уровне дочернего компонента, использовать абстрактный класс в качестве маркера внедрения и для стратегии useExisting
. Это позволит вам запросить один токен, чтобы получить все ваши дочерние элементы контента определенного типа. Вот пример:
abstract class MyDumbComponent {
// some properties here
// some methods here
};
@Component({
selector: 'my-dumb-component',
providers: [
{ provide: MyDumbComponent, useExisting: DumbComponentA }
]
})
export class DumbComponentA implements MyDumbComponent {
...
}
Обратите внимание, я использую абстрактный токен для токена здесь, потому что интерфейсы исчезнут после переноса, и во-вторых, мне нравится определять некоторый общий "интерфейс" для компонентов, имеющих те же методы.
В родительском компоненте вы можете запросить их следующим образом:
@Component({
...
})
export class ParentSmartComponent { }
@ContentChildren(MyDumbComponent) myDumbComponents: QueryList<MyDumbComponent>;
ngAfterContentInit() {
// here you'll have access to your dumb components
}
}
Третий, предпочтительный подход заключается в использовании @Output
. Хотя в некоторых случаях вышеприведенное работает нормально, и, если я вас правильно понял, вы хотите общаться с дочерними компонентами с родительским компонентом. Все вышеперечисленное помещает родительский компонент в рабочее место водителя, что означает, что он на самом деле не перечисляет некоторые события, а скорее получает доступ к дочерним API. @Output
с другой стороны, позволяют ребенку уведомить своего родителя о том, что что-то произошло. Затем родитель может прослушать это событие и выполнить какой-либо метод или задачу.
Как уже упоминалось, это в большинстве случаев предпочтительный способ связи между дочерними и родительскими компонентами, потому что он не будет тесно связывать ваши дочерние компоненты с родительским компонентом и наоборот. Глупые компоненты остаются очень многократно используемыми и отправляют только внешние события, которые родительские компоненты могут затем прослушивать и действовать соответственно.
Это также позволяет вам составлять ваши компоненты так, как вам нравится. Вы можете использовать любой немой компонент внутри вашего интеллектуального компонента. Единственное требование здесь - чтобы они генерировали события для уведомления своего родителя.
Ради полноты вы можете также добавить ваш смарт-компонент в ваш немой компонент. Вот как это будет выглядеть:
@Component({
...
})
export class MyDumbComponent {
constructor(private smartComponent: ParentSmartComponent) { }
}
Однако я бы также не рекомендовал такой подход, поскольку он, опять же, тесно связывает ваши немые компоненты с вашими интеллектуальными компонентами. Как уже упоминалось @ n-sokolowski, проекция контента может использоваться как средство для компоновки, и ваши составные компоненты должны быть как можно более повторными и универсальными.
Чтобы подвести итог, просто используйте @Output
внутри вашего тупого компонента и генерируйте определенные события, которые родительские компоненты могут затем прослушивать.