Используйте родительскую область видимости / методы / атрибуты в включенных компонентах
Я пытаюсь использовать transclusion n angular6 и не могу получить прямой обзор.
<component-smart1
[someObject]="myObject"
[someService]="saidService">
<component-dumb-1
[specificObject]="getSpecificObject()"></component-dumb-1>
<component-dumb-2
[specificObject]="getSpecificObject()"
(someEvent)="handleEvent()"></component-dumb-2>
</component-smart1>
Теперь я хочу тупые компоненты (component-dumb-1
, component-dumb-2
) использовать умные компоненты (component-smart1
) область применения / методы / атрибуты.
Моя цель состоит в том, чтобы иметь возможность составлять разные варианты с разными компонентами в включении, используя одни и те же методы из интеллектуальных компонентов. Например:
<component-smart1
[someObject]="myObject"
[someService]="saidService">
<component-dumb-1
[specificObject]="getSpecificObject()"></component-dumb-1>
<component-dumb-2
[specificObject]="getSpecificObject()"
(someEvent)="handleEvent()"></component-dumb-2>
<component-dumb-3
[specificObject]="getSpecificObject()"
(someOtherEvent)="handleOtherEvent()"></component-dumb-3>
</component-smart1>
Это возможно?
2 ответа
Прежде всего, в 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
"S. Хотя в некоторых случаях вышеприведенное работает нормально, и, если я вас правильно понял, вы хотите общаться с дочерними компонентами с родительским компонентом. Все вышеперечисленное помещает родительский компонент в рабочее место водителя, что означает, что он на самом деле не перечисляет некоторые события, а скорее получает доступ к дочерним API. @Output
с другой стороны, позволяют ребенку уведомить своего родителя о том, что что-то произошло. Затем родитель может прослушать это событие и выполнить какой-либо метод или задачу.
Как уже упоминалось, это в большинстве случаев предпочтительный способ связи между дочерними и родительскими компонентами, потому что он не будет тесно связывать ваши дочерние компоненты с родительским компонентом и наоборот. Глупые компоненты остаются очень многократно используемыми и отправляют только внешние события, которые родительские компоненты могут затем прослушивать и действовать соответственно.
Это также позволяет вам составлять ваши компоненты так, как вам нравится. Вы можете использовать любой немой компонент внутри вашего интеллектуального компонента. Единственное требование здесь - чтобы они генерировали события для уведомления своего родителя.
Для полноты вы можете также вставить ваш смарт-компонент в ваш немой компонент. Вот как это будет выглядеть:
@Component({
...
})
export class MyDumbComponent {
constructor(private smartComponent: ParentSmartComponent) { }
}
Однако я бы также не рекомендовал такой подход, поскольку он, опять же, тесно связывает ваши немые компоненты с вашими интеллектуальными компонентами. Как уже упоминалось @ n-sokolowski, проекция контента может использоваться как средство для компоновки, а ваши составные компоненты должны быть как можно более повторными и универсальными.
Подводя итог, просто используйте @Output
находится внутри вашего немого компонента и испускает определенные события, которые родительские компоненты могут затем прослушивать.
Привет, я думаю, что вы пытаетесь сделать вид общего smart-component
и хочу своих детей (через ng-content
) иметь доступ к своей области вместо области компонента, в которой вы написали этот шаблон. Я думаю, это невозможно, и это немного ошибочное представление о том, что делает Transclusion.
Smart-Component часто очень специфичны, и это нормально, что они связаны с конкретным маршрутом и прочим. Если бы это было не так, у вас было бы много тяжелых вещей (например, инъекционных услуг), которые, вероятно, не нужны в каждой конкретной ситуации.
Transclusion помогает составлять немые компоненты, если вы их правильно спроектировали. Поэтому они должны быть максимально общими или гибкими.