Используйте родительскую область видимости / методы / атрибуты в включенных компонентах

Я пытаюсь использовать 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 помогает составлять немые компоненты, если вы их правильно спроектировали. Поэтому они должны быть максимально общими или гибкими.

Другие вопросы по тегам