2

Still new to angular 2 and trying to figure out how to best make reusable popups. I found this very handy popup from a different question on SO (Angular 2.0 and Modal Dialog)

@Component({
  selector: 'app-component',
  template: `
  <button type="button" (click)="modal.show()">test</button>
  <app-modal>
    <div class="app-modal-header">
      header
    </div>
    <div class="app-modal-body">
      Whatever content you like, form fields, anything
    </div>
    <div class="app-modal-footer">
      <button type="button" class="btn btn-default" (click)="modal.hide()">Close</button>
      <button type="button" class="btn btn-primary">Save changes</button>
    </div>
  </app-modal>
  `
})
export class AppComponent {

  @ViewChild(ModalComponent)
  public readonly modal: ModalComponent;
}

@Component({
  selector: 'app-modal',
  template: `
  <div (click)="onContainerClicked($event)" class="modal fade" tabindex="-1" [ngClass]="{'in': visibleAnimate}"
       [ngStyle]="{'display': visible ? 'block' : 'none', 'opacity': visibleAnimate ? 1 : 0}">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <ng-content select=".app-modal-header"></ng-content>
        </div>
        <div class="modal-body">
          <ng-content select=".app-modal-body"></ng-content>
        </div>
        <div class="modal-footer">
          <ng-content select=".app-modal-footer"></ng-content>
        </div>
      </div>
    </div>
  </div>
  `
})
export class ModalComponent {

  public visible = false;
  private visibleAnimate = false;

  public show(): void {
    this.visible = true;
    setTimeout(() => this.visibleAnimate = true, 100);
  }

  public hide(): void {
    this.visibleAnimate = false;
    setTimeout(() => this.visible = false, 300);
  }

  public onContainerClicked(event: MouseEvent): void {
    if ((<HTMLElement>event.target).classList.contains('modal')) {
      this.hide();
    }
  }
}

I am making an application that will have multiple popups throughout. I'd love to keep this simple html template, and insert different child components depending on what popup I want. Ie replacing the popup div;

<div class="modal-dialog">
  <div class="modal-content">
    <my-custom-component></my-custom-component>
  </div>
</div>

is there a way to 'pass in' the my-custom-component? Or will I have to duplicate the popup html for each type of popup I want?

Community
  • 1
  • 1
will
  • 1,397
  • 5
  • 23
  • 44

2 Answers2

4

This looks like a perfect case for using Angular 2 transclusion. Transclusion - scary word but actually it's dead simple.

In your modal component template you should just put:

<ng-conten></ng-content>

After that you will be able to use your modal component in other template like this:

<app-modal>
  <-- your custom content -->
  <div></div>
</app-modal>

If you want specific sections, you can put several ng-content tags with select attribute set to some values:

<ng-conten select=[header]></ng-content>
<ng-conten select=[body]></ng-content>
<ng-conten select=[footer]></ng-content>

And in the usage place:

<app-modal>
 <-- your custom content -->
 <div class="someClass" header></div>
 <div class="maybeSomeOtherClass" body></div>
 <div footer></div>
</app-modal>

You can find more detailed info in this great article.

vezucci
  • 386
  • 2
  • 11
  • guess my code sample already had this built in, just did not know it existed/what it was! thanks :) – will May 06 '17 at 00:22
0

You could create a component/template that uses ngSwitch, and pass that component what it needs to decide which template to load, in this example just a string to switch off, but you can pass it whatever data you might need to trigger the sub-template's behavior. So you'd call your component in html like so :

<my-custom-component [templateToUse]='template2'></my-custom-component>

And then in the code for the component have an @Input for that property, I'm assuming you know how to do that. Then in the template for the component you put in your ngSwitch statement.

Taking my example from the angular docs, as I've yet to have to use ngSwitch in ng2, but have in angular 1.x. See here for more info. https://angular.io/docs/ts/latest/api/common/index/NgSwitch-directive.html I'm preserving the container/some-element names, but they're just there I believe to show the nesting structure.

(my-custom-component.html)

<container-element [ngSwitch]="templateToUse">
   <some-element *ngSwitchCase="template1">Template could be another component/directive</some-element>
    <some-element *ngSwitchCase="template2">I chose this template</some-element>
</container-element>
chairmanmow
  • 649
  • 7
  • 20