Используйте родительскую область видимости / методы / атрибуты в включенных компонентах - PullRequest
0 голосов
/ 27 июня 2018

Я пытаюсь использовать 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 ]

0 голосов
/ 02 июля 2018

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

0 голосов
/ 28 июня 2018

Привет. Я думаю, что вы пытаетесь создать что-то общее smart-component и хотите, чтобы его дочерние элементы (через ng-content) имели доступ к своей области вместо области компонента, в которой вы написали этот шаблон. Я думаю, это невозможно, и это немного ошибочное представление о том, что делает Transclusion.

Smart-Component часто очень специфичен, и вполне нормально, что он привязан к определенному маршруту и ​​прочим вещам. Если бы это было не так, вы бы в конечном итоге получили там много тяжелых вещей (например, инъекционных услуг), которые, вероятно, не нужны в каждой конкретной ситуации.

Transclusion помогает составлять немые компоненты, если вы их правильно спроектировали. Поэтому они должны быть максимально общими или гибкими.

...