1

I have a typical Angular 2 app with many components.
I installed this modal component: https://github.com/pleerock/ng2-modal.
Is there a way to share the same modals between more components? I explain better. I would like the same modal should open on click of different buttons inside different components. Is it possible?

I tried this kind of approach https://plnkr.co/edit/RgI1e9PobC7FloLHpEFD?p=preview but it's not the right way, because it always adds content to the modal.

I post it here below my app.ts file:

21/12/2016 update
Following @echonax suggestion, I updated my plunk:

//our root app component
import {
  NgModule, 
  ComponentRef, 
  Injectable, 
  Component, 
  Injector, 
  ViewContainerRef, 
  ViewChild, ComponentFactoryResolver} from "@angular/core";
import {BrowserModule} from '@angular/platform-browser'
import {Subject} from 'rxjs/Subject';

@Injectable()
export class SharedService {
  showModal:Subject<any> = new Subject();
}


@Component({
  selector: 'child-component',
  template: `
      <button (click)="showDialog()">show modal from child</button>
  `,
})
export class ChildComponent {
  constructor(private sharedService:SharedService) {}

  showDialog() {
    this.sharedService.showModal.next(CompComponent);
  }

}


@Component({
  selector: 'comp-comp',
  template: `MyComponent`
})
export class CompComponent { }


@Component({
  selector: 'modal-comp',
  template: `
  <div class="modal fade" id="theModal" tabindex="-1" role="dialog" aria-labelledby="theModalLabel">
    <div class="modal-dialog largeWidth" role="document">
      <div class="modal-content">
        <div class="modal-header">
        <h4 class="modal-title" id="theModalLabel">The Label</h4></div>
        <div class="modal-body" #theBody>
      </div>
    <div class="modal-footer">
    <button type="button" class="btn btn-default" data-dismiss="modal" (close)="close()">Close</button>
  </div></div></div></div>
`
})
export class ModalComponent {
  @ViewChild('theBody', {read: ViewContainerRef}) theBody;

  cmp:ComponentRef<any>;
  cmpRef:ComponentRef<any>;

  constructor(
    sharedService:SharedService, 
    private componentFactoryResolver: ComponentFactoryResolver, 
    injector: Injector) {

    sharedService.showModal.subscribe(type => {
      if(this.cmp) {
        this.cmp.destroy();
      }
      let factory = this.componentFactoryResolver.resolveComponentFactory(type);
      this.cmpRef = this.theBody.createComponent(factory)
      $('#theModal').modal('show');
    });
  }

  close() {
    if(this.cmp) {
      this.cmp.destroy();
    }
    this.cmp = null;
  }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello</h2>
      <button (click)="showDialog()">show modal</button>
      <child-component></child-component>
    </div>
  `,
})
export class App {
  constructor(private sharedService:SharedService) {}

  showDialog() {
    this.sharedService.showModal.next(CompComponent);
  }

}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, ModalComponent, CompComponent, ChildComponent],
  providers: [SharedService],
  entryComponents: [CompComponent],
  bootstrap: [ App, ModalComponent ]
})
export class AppModule{}

Stay tuned!

B. Ciervo
  • 135
  • 4
  • 16
  • What have you tried? Try to reference it, and post the code that is not working, to try to get help. People will respond with more help when you have tried something and just need a fix, rather than asking someone to do it for you. – Steven Scott Dec 20 '16 at 21:12
  • Ok I did. Anyway, any of the approaches I tried fit what I needed so I didn't think it was useful to post them. I tried the whole yesterday afternoon, it was't laziness. – B. Ciervo Dec 21 '16 at 09:42
  • 1
    That plunker's original version is my question actually: http://stackoverflow.com/questions/36566698/how-to-dynamically-create-bootstrap-modals-as-angular2-components and @Günter made an amazing answer which I think is really underrated. It has a small mistake, I'll tell Günter about it but you can find the fixed version here: https://plnkr.co/edit/oMCZIJq58WdLgYf2D0Di?p=preview – eko Dec 21 '16 at 09:46
  • And where did you get that plunker(just curious)? – eko Dec 21 '16 at 09:55
  • 1
    @echonax thank you so much! I try to implement it in my code, I'll let you know. – B. Ciervo Dec 21 '16 at 10:01
  • @echonax Sorry but... I don't remember where I found it, I surfed the web all yesterday afternoon! – B. Ciervo Dec 21 '16 at 10:02
  • @B.Ciervo no problem, let's see if it works – eko Dec 21 '16 at 10:04
  • @echonax it gives me two errors. I'll edit my answer so you could see them. Thanks again. – B. Ciervo Dec 21 '16 at 10:52
  • Change cmpRef's to `:ComponentRef;` and `$` error is there because I use `jQuery` in my app – eko Dec 21 '16 at 10:57
  • Yeah sorry, I made that change on my local app but not on Plunker. But the error is on "type", not on cmpRef... however, I'm trying to find the solution... – B. Ciervo Dec 21 '16 at 11:03
  • 1
    Ok, it was because the service SharedService had to be written like this: `showModal:Subject = new Subject();` ;) – B. Ciervo Dec 21 '16 at 11:12
  • @echonax thanks a lot! This was what I needed. If you put your comment as an asnwer, I'll check it ;) – B. Ciervo Dec 22 '16 at 14:54

2 Answers2

2

That plunker's original version is my question actually: How to dynamically create bootstrap modals as Angular2 components?

@Günter made an amazing answer which I think is really underrated.

The plunker has a small mistake, you can find the fixed version here: https://plnkr.co/edit/oMCZIJq58WdLgYf2D0Di?p=preview

The if cases are referencing the wrong field, so change

if(this.cmp) {
    this.cmp.destroy();
}

with

if(this.cmpRef) {
    this.cmpRef.destroy();
}
Community
  • 1
  • 1
eko
  • 39,722
  • 10
  • 72
  • 98
2

I know this topic is 6 months old, but it was a really deal for me to achieve a such thing.

So I made a npm module to allow modal sharing between components with shared data and remote opening / closing / events.

Feel free to check it out : https://github.com/biig-io/ngx-smart-modal.

The demo is here : https://biig-io.github.io/ngx-smart-modal/

Compatible with Angular >=2.0.0

Maxime Lafarie
  • 2,172
  • 1
  • 22
  • 41