Построение директивы обертки (перенос некоторого содержимого/компонента) в angular2

Я довольно новые директивы здания с Angular2. Я хочу создать директиву всплывающих окон, которая будет обертывать содержимое некоторыми классами css.

Контент

Содержимое может быть чистым текстом и заголовками, например:

<div class="data">
    <h2>Header</h2>
    Content to be placed here.
</div>

Затем я хочу дать этому атрибуту директивы, например: всплывающее окно

<div class="data" popup>
    <h2>Header</h2>
    Content to be placed here.
</div>

Что должна сделать директива, заключается в том, чтобы обернуть div внутри, скажем:

<div class="some class">
    <div class="some other class">
        <div class="data">
            <h2>Header</h2>
            Content to be placed here.
        </div>
    </div>
</div>

Случай, который я описал до сих пор, является атрибутом или структурными директивами.

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: `[popup]`
})

export class PopupDirective {


}

Ответ 1

Другой ответ связан, но отличается.

Для более подробного ознакомления смотрите следующее: Как условно обернуть div вокруг ng-content - мое решение для Angular 4, но у связанного вопроса есть некоторые подсказки о том, как это можно сделать для Angular 2.

Я решил эту проблему вместе с компонентом и директивой. Мой компонент выглядит примерно так:

import { Component, Input, TemplateRef } from '@angular/core';

@Component({
  selector: 'my-wrapper-container',
  template: '
<div class="whatever">
  <ng-container *ngTemplateOutlet="template"></ng-container>
</div>
'
})
export class WrapperContainerComponent {
  @Input() template: TemplateRef<any>;
}

и моя директива такова:

import { Directive, OnInit, Input, TemplateRef, ComponentRef, ComponentFactoryResolver, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[myWrapperDirective]'
})
export class WrapperDirective implements OnInit {

  private wrapperContainer: ComponentRef<WrapperContainerComponent>;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainerRef: ViewContainerRef,
    private componentFactoryResolver: ComponentFactoryResolver
  ) { }

  ngOnInit() {
    const containerFactory = this.componentFactoryResolver.resolveComponentFactory(WrapperContainerComponent);
    this.wrapperContainer = this.viewContainerRef.createComponent(containerFactory);
    this.wrapperContainer.instance.template = this.templateRef;
  }
}

Чтобы иметь возможность загружать ваш компонент динамически, вам нужно перечислить ваш компонент как entryComponent внутри вашего модуля:

@NgModule({
  imports: [CommonModule],
  declarations: [WrapperContainerComponent, WrapperDirective],
  exports: [WrapperContainerComponent, WrapperDirective],
  entryComponents: [WrapperContainerComponent]
})
export class MyModule{}

поэтому HTML в конце концов:

<some_tag *myWrapperDirective />

Который отображается как:

<my-wrapper-container>
  <div class="whatever">
    <some_tag />
  </div>
</my-wrapper-container>

Ответ 2

Вы можете добиться этого с помощью селектора атрибутов компонента и Angular 2 Content Projection <ng-content>

@Component({
  selector: 'my-app',
  template: `
    <div class="app"> 
        <div class="data" myWrapper>
            <h2>Header</h2>
            Content to be placed here.
        </div> 
    </div>
  `
})
export class AppComponent {}


@Component({
  selector: '[myWrapper]',
  template: `
    <div class="my-class">
      <div class="my-sub-class">
          <ng-content></ng-content>
      </div>
    </div>
  `
})
export class MyComponent {

}