import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { Popup } from "./popup.component";
import { PopupService } from "./popup.service";
import { PopupA } from './popups/a.component';
import { PopupB } from './popups/b.component';

@NgModule({
  imports: [
    BrowserModule
  ],
  providers: [PopupService],
  declarations: [
    AppComponent, Popup, PopupA, PopupB
  ],
  entryComponents: [PopupA, PopupB],
  bootstrap: [ AppComponent ]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
<!DOCTYPE html>
<html>
  <head>
    <title>Popup example</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">

    <!-- Polyfills for older browsers -->
    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>

    <script src="https://unpkg.com/zone.js@0.6.25?main=browser"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.8"></script>
    <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>

    <script src="https://cdn.rawgit.com/angular/angular.io/f2daab7/public/docs/_examples/_boilerplate/systemjs.config.web.js"></script>
    
  </head>

  <body app-root></body>
</html>
import { Component } from "@angular/core";
import { Popup } from "./popup.component";
import { PopupService } from './popup.service';
import { PopupA } from './popups/a.component';
import { PopupB } from './popups/b.component';

@Component({
  selector: "[app-root]",
  directives: [Popup],
  templateUrl: "app/app.component.html"
})
export class AppComponent {
  
 constructor(private popupService: PopupService) {}
 
 openA() {
   this.popupService.open(PopupA, [
     {
       provide: "id", useValue: "hello from a"
     }
   ]);
 }
 
  openB() {
   this.popupService.open(PopupB, [
     {
       provide: "id", useValue: "hello from b"
     }
   ]);
 }
}
<div cass="container">
  <div class="row padding">
    <popup-overflow></popup-overflow>
    <button (click)="openA()" class="btn btn-primary btn-lg">Open popup A</button>
    <button (click)="openB()" class="btn btn-default btn-lg">Open popup B</button>
  </div>
</div>
.padding{
  padding: 20px;
}

.loader {
  background-color: #000000;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 9999;
  position: absolute;
  opacity: 0.4;
}

.spinner {
  margin: 100px auto;
  width: 50px;
  height: 40px;
  text-align: center;
  font-size: 10px;
}

.spinner > div {
  background-color: #333;
  height: 100%;
  width: 6px;
  display: inline-block;
  
  -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
  animation: sk-stretchdelay 1.2s infinite ease-in-out;
}

.spinner .rect2 {
  -webkit-animation-delay: -1.1s;
  animation-delay: -1.1s;
}

.spinner .rect3 {
  -webkit-animation-delay: -1.0s;
  animation-delay: -1.0s;
}

.spinner .rect4 {
  -webkit-animation-delay: -0.9s;
  animation-delay: -0.9s;
}

.spinner .rect5 {
  -webkit-animation-delay: -0.8s;
  animation-delay: -0.8s;
}

@-webkit-keyframes sk-stretchdelay {
  0%, 40%, 100% { -webkit-transform: scaleY(0.4) }  
  20% { -webkit-transform: scaleY(1.0) }
}

@keyframes sk-stretchdelay {
  0%, 40%, 100% { 
    transform: scaleY(0.4);
    -webkit-transform: scaleY(0.4);
  }  20% { 
    transform: scaleY(1.0);
    -webkit-transform: scaleY(1.0);
  }
}
.modal.in {
  display: block;
}
import {
  Component, OnDestroy, OnInit, ReflectiveInjector, Injector, ComponentFactoryResolver
} from '@angular/core';
import {PopupService, PopupEvent} from './popup.service';
import {ViewContainerRef} from '@angular/core';
import {Subscription} from 'rxjs/Subscription';
import { PopupA } from './popups/a.component';
import { PopupB } from './popups/b.component';

@Component({
  selector: 'popup-overflow',
  templateUrl: 'app/popup.component.html'
  
})
export class Popup implements OnDestroy, OnInit {
  loading: false;
  subscribers: Array<Subscription> = [];
  constructor(private popupService: PopupService,
              private injector: Injector,
              private componentFactoryResolver: ComponentFactoryResolver,
              private viewContainerRef: ViewContainerRef) {
  }


  ngOnInit() {
    this.subscribers.push(
      this.popupService.subscribe((data) => {
        if (!!data && data.operation === PopupEvent.OPEN) {
          this.open(data);
        } else if (data &&
          (
            data.operation === PopupEvent.CLOSE ||
            data.operation === PopupEvent.DESTROY
          )
        ) {
          this.close();
        }
      })
    );
  }

  ngOnDestroy() {
    if (this.subscribers) {
      this.subscribers.forEach(item => item.unsubscribe());
      this.subscribers = null;
    }
  }

  private open(data) {
    this.loading = true;
    let providers = data.providers || [];
    let injector = ReflectiveInjector.resolveAndCreate(providers, this.injector);
    let factory = this.componentFactoryResolver.resolveComponentFactory(data.component);
  
    setTimeout(() => {
      this.loading = false;
      this.viewContainerRef.createComponent(factory, 0, injector);
    }, 1000);
  }

  private close() {
    this.viewContainerRef.detach(0);
  }
}
import {Injectable, EventEmitter} from '@angular/core';

export enum PopupEvent {
  OPEN, DESTROY, CLOSE
}


@Injectable()
export class PopupService {


  private currentPopupView: EventEmitter<any> = new EventEmitter<any>();
  private _isOpened: boolean = false;

  
  isOpened(): boolean {
    return this._isOpened;
  }

  open(component: any, providers?: Array<any>): void {
    if (this._isOpened) {
      this.destroy();
    }
    this.fireEvent(PopupEvent.OPEN, true, {
      component: component,
      providers: providers
    });
  }

 
  destroy() {
    this.fireEvent(PopupEvent.DESTROY, false);
  }

  
  close(): void {
    this.fireEvent(PopupEvent.CLOSE, false);
  }
  
  subscribe(generatorOrNext?: any, error?: any, complete?: any) {
   this.currentPopupView.subscribe(generatorOrNext, error, complete);
  }

  private fireEvent(name: PopupEvent, status: boolean, data?: any) {
    let _current = this._isOpened;
    this._isOpened = status;
    let event = {
      operation: name,
      status: {
        current: this._isOpened,
        old: _current
      },
    };
    if (typeof data === "object" && data != null) {
      Object.assign(event, data);
    }
    this.currentPopupView.emit(event);
  }

}
<div [ngClass]="{'loader': loading}" >
  <div *ngIf="loading" class="spinner">
    <div class="rect1"></div>
    <div class="rect2"></div>
    <div class="rect3"></div>
    <div class="rect4"></div>
    <div class="rect5"></div>
  </div>
</div>
import {Component, OnInit, Inject} from '@angular/core';
import {PopupService} from '../popup.service';

@Component({
  selector: 'popup-a-view',
  templateUrl: "app/popups/a.component.html"
})
export class PopupA {
  id: string;
  constructor(
    private popupService: PopupService,
    @Inject("id") id: string
  ) {
      this.id = id;
  }

  close() {
   this.popupService.close();
  }
}
import {Component, OnInit, Inject} from '@angular/core';
import {PopupService} from '../popup.service';

@Component({
  selector: 'popup-b-view',
  templateUrl: "app/popups/b.component.html"
})
export class PopupB {
  id: string;
  constructor(
    private popupService: PopupService,
    @Inject("id") id: string
  ) {
    this.id = id;
  }

  close() {
   this.popupService.close();
  }
}
<div class="modal fade in">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">Modal title A</h4>
      </div>
      <div class="modal-body">
         This is popup a: {{ id }}
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" (click)="close()">Close</button>
      </div>
    </div>
  </div>
</div>
<div class="modal fade in">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">Modal title B</h4>
      </div>
      <div class="modal-body">
         This is popup b: {{ id }}
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-default" (click)="close()">Close</button>
      </div>
    </div>
  </div>
</div>