Angular 2 ng-bootstrap Modal: How to pass data to entry component

27,190

Solution 1

Just provide a service and inject it to VideoModalComponent and PageComponent then you can use this service to communicate.

See https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service for more details and examples.

Solution 2

I solved it! Here's how to do it:

  • In the component(from where you are opening the modal) do this:

    const modalRef = this.modalService.open(ModalComponent);
    
    modalRef.componentInstance.passedData= this.dataToPass;
    
    modalRef.result.then(result => {
      //do something with result
    }                                                       
    
  • In the modal component(receiving end):

    export class ModalComponent { 
    
     passedData: typeOfData;     // declare it!
    
     someFunction() {     // or some  lifecycle hook 
      console.log(this.passedData)  // and then, use it!
     }
    
    // rest of the ModalComponent 
    }
    
Share:
27,190
asabido
Author by

asabido

Updated on July 05, 2022

Comments

  • asabido
    asabido almost 2 years

    I'm trying to send data to a custom modal content component so I can call it from any other component and not repeat code. I'm new to Angular 2 and have followed the "Components as content" demo of ng-boostrap as well as the "Component Interaction" in the Angular docs and have not found a way to get this to work or an example for this case.

    I can get the modal to open, but not with dynamic content. I've tried the @Input and the variable approach with no success. I've also added ModalService to the providers in app.module.ts. This is what I have with both approaches that doesn't work:

    page.component.html:

    <a (click)="modal('message')">
    <template ngbModalContainer><my-modal [data]="data"></my-modal></template>
    

    page.component.ts:

    import { Component } from '@angular/core'
    import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
    import { ModalService } from '../helpers/modal.service'
    import { ModalComponent } from '../helpers/modal.component'
    
    @Component({
      selector: 'app-page',
      templateUrl: './page.component.html',
      styleUrls: ['./page.component.scss'],
      entryComponents: [ ModalComponent ]
    })
    
    export class PageComponent {
      data = 'customData'
      constructor (
        private ngbModalService: NgbModal,
        private modalService: ModalService
       ) { }
    
      closeResult: string
      modal(content) {
        this.data = 'changedData'
        this.modalService.newModal(content)
        this.ngbModalService.open(ModalComponent).result.then((result) => {
          this.closeResult = `Closed with: ${result}`
        }, (reason) => {
          this.closeResult = `Dismissed ${reason}`
        });
      }
    }
    

    modal.service.ts:

    import { Injectable } from '@angular/core';
    import { Subject }    from 'rxjs/Subject';
    
    @Injectable()
    export class ModalService {
      private modalSource = new Subject<string>()
      modal$ = this.modalSource.asObservable()
      newModal(content: string) {
        this.modalSource.next(content)
      }
    }
    

    modal.component.ts:

    import { Component, Input, OnDestroy } from '@angular/core';
    import { Subscription }   from 'rxjs/Subscription';
    import { ModalService } from './modal.service'
    
    @Component({
      selector: 'my-modal',
      template: `
        <div class="modal-body">
        {{data}}
        {{content}}
        </div>
      `
    })
    
    export class ModalComponent implements OnDestroy {
      @Input() data: string
      content = 'hello'
    
      subscription: Subscription
      constructor(
        private modalService: ModalService
      ) {
        this.subscription = modalService.modal$.subscribe(
          content => {
            this.content = content
        });
      }
    
      ngOnDestroy() {
        this.subscription.unsubscribe();
      }
    }
    

    Using angular v2.1.0, angular-cli v1.0.0-beta.16, ng-bootstrap v1.0.0-alpha.8

  • asabido
    asabido over 7 years
    Thanks Günter, I went back and implemented the service (see edited entry) but it's still not working. Perhaps the ngbModalService is creating a new instance of my modal component so they're not communicating. Any ideas seeing the update?
  • ZooZ
    ZooZ over 7 years
    Either provide the service in the root component or make it a singleton service. It should work.
  • Günter Zöchbauer
    Günter Zöchbauer over 7 years
    Where do you provide ModalService? How many instances you get depends on where you provide it. If you add it to providers of a component, each such component will get it's own instance. If you add it to providers of @NgModule() (non-lazy loaded) then only one instance is created for the whole app.
  • asabido
    asabido over 7 years
    @GünterZöchbauer I've tried including ModalService as a provider in @ngModule() and then tried in PageComponent and neither work.
  • Günter Zöchbauer
    Günter Zöchbauer over 7 years
    Can you try to reproduce in Plunker (they have a working Angular2 TS template)
  • Günter Zöchbauer
    Günter Zöchbauer over 7 years
    The problem seems to be that the observable emits the value before the subscription is set up. If you use a BehaviorSubject instead, then the subscriber gets the last emitted value immediately after subscribing. plnkr.co/edit/y28ppeYk7ZQ4nsOFmIi1?p=preview
  • Elysiumplain
    Elysiumplain about 5 years
    make sure you aren't declaring the incoming data with prefix @Input
  • Maayao
    Maayao almost 5 years
    @Elysiumplain can you explain more (reasoning)?
  • Elysiumplain
    Elysiumplain almost 5 years
    @Maayao It has been a long time, but IIRC it has to do with the was Angular's internals treat variable handling; with @Input() and Services like modalService declaration not sharing the same namespace. *note that this may have changed with newer version