Ngx-bootstrap: how to call modal from parent component,

Created on 17 Jun 2016  Â·  23Comments  Â·  Source: valor-software/ngx-bootstrap

I am using ng2-bootstrap for the modal stuff.

I am trying to separate my modals and my other components apart. So I have the following files:

_addPlaylist.modal.ts_

import {Component} from '@angular/core';
import {CORE_DIRECTIVES} from '@angular/common';


import {MODAL_DIRECTVES, BS_VIEW_PROVIDERS} from 'ng2-bootstrap/ng2-bootstrap';

@Component({
  selector: 'addplaylist-modal',
  directives: [MODAL_DIRECTVES, CORE_DIRECTIVES],
  viewProviders: [BS_VIEW_PROVIDERS],
  templateUrl: 'app/channel/modals/addPlaylistModal.html'
})

export class AddPlaylistModalComponent {
  constructor() {
    console.log(this);
  }
}

_addPlaylistModal.html_

<div bsModal #lgModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-lg">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" (click)="lgModal.hide()" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
        <h4 class="modal-title">Large modal</h4>
      </div>
      <div class="modal-body">
        ...
      </div>
    </div>
  </div>
</div>

In it's parent component's html I have code piece like this:

  <a (click)="lgModal.show()"><span class="bigplus pull-right"></span></a>
   //some other code
  <addplaylist-modal></addplaylist-modal>

This is the parent component:
_channel.component.ts_

import { AddPlaylistModalComponent } from './shared/addPlaylist.modal';

@Component({
  selector: 'channel',
  styleUrls: ['app/channel/channel.css'],
  directives: [PlatformsComponent, PagesComponent, PlaylistComponent, VideosComponent, AddPlaylistModalComponent],
  providers: [PlatformService],
  templateUrl: 'app/channel/channel.html'
})

What I want to do, I want to be able to let the parent componet to access it and open the modal even if I write the (click)="lgModal.show()" at parent component.

Now if I click the <a (click)="lgModal.show()"><span class="bigplus pull-right"></span></a> , it will say “ can not read property show of undefined"

So, how to let the parent component know that the lgModal is defined and it's in its child component.

Most helpful comment

@xinrui-ma
I tried this and its working fine for me.
Below is added in parent html :
<custom-modal #modal></custom-modal>
then on click of below is the snipped added in parent html :
<a (click)="modal.showModal(description)" class="more">
then below is the modal component :

import {MODAL_DIRECTVES, BS_VIEW_PROVIDERS} from 'ng2-bootstrap/ng2-bootstrap';
import {Component, ViewChild, ElementRef} from "@angular/core";

@Component({
    selector: 'custom-modal',
    moduleId: module.id,
    templateUrl: './modal.component.html',
    styleUrls: ['./modal.component.css'],
    directives: [MODAL_DIRECTVES],
    viewProviders: [BS_VIEW_PROVIDERS]
})

export class ModalComponent {
    modalBody:string;
    @ViewChild('lgModal') modal:ElementRef;

    showModal(modalBody:string) {
        if (modalBody != undefined) {
            this.modalBody = modalBody;
            this.modal.show();
        }
    }
}

and modal template is :

<div bsModal #lgModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel"
     aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" (click)="lgModal.hide()" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">Description</h4>
            </div>
            <div class="modal-body">
                {{modalBody}}
            </div>
        </div>
    </div>
</div>

Please let me know your thoughts on it.
Working fine for me.

All 23 comments

+1

@xinrui-ma
I tried this and its working fine for me.
Below is added in parent html :
<custom-modal #modal></custom-modal>
then on click of below is the snipped added in parent html :
<a (click)="modal.showModal(description)" class="more">
then below is the modal component :

import {MODAL_DIRECTVES, BS_VIEW_PROVIDERS} from 'ng2-bootstrap/ng2-bootstrap';
import {Component, ViewChild, ElementRef} from "@angular/core";

@Component({
    selector: 'custom-modal',
    moduleId: module.id,
    templateUrl: './modal.component.html',
    styleUrls: ['./modal.component.css'],
    directives: [MODAL_DIRECTVES],
    viewProviders: [BS_VIEW_PROVIDERS]
})

export class ModalComponent {
    modalBody:string;
    @ViewChild('lgModal') modal:ElementRef;

    showModal(modalBody:string) {
        if (modalBody != undefined) {
            this.modalBody = modalBody;
            this.modal.show();
        }
    }
}

and modal template is :

<div bsModal #lgModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel"
     aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" (click)="lgModal.hide()" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">Description</h4>
            </div>
            <div class="modal-body">
                {{modalBody}}
            </div>
        </div>
    </div>
</div>

Please let me know your thoughts on it.
Working fine for me.

@harishrohokale Thanks for your solution, it works!
I have two questions though,

  1. if I add moduleId: module.id, it would compile, lint error 'can't find name module, what the purpose add this line here?
  2. lint error, property 'show' does not exist on type 'ElementRef'

Any thoughts?

I'm trying to do the opposite, i have my modal on grandparent component and i want to trigger that modal 3 down level children.

@xinrui-ma Hey, did you solve that lint issue ?

@thohoh Hey, I still did not, you?I mean, property 'show' does not exist on type ElementRef, I have to change it to type any to avoid that issue but I don't think this is a correct way.

@xinrui-ma Just specify type of any since this is a reference variable on the template.

@ViewChild('lgModal') myModal: any;

Also in parent component I made a reference to the modalComponent via:

@ViewChild(ModalComponent) myModal: ModalComponent;

@harishrohokale Thanks. This was really, really helpful.

@thohoh Thanks for the solution on tslint error.

Also Why do we need to use @ViewChild(ModalComponent) myModal: ModalComponent; in parent component?

Since we are calling modal component from HTML itself by using modal.showModal(desc).

if we used
@ViewChild(ModalComponent) myModal: ModalComponent;
in the parent, can we then call a modal in the JS rather than the HTML by using myModal.show(desc) ?
or is more needed in order to do this?

@BenevidesLecontes for a grandparent to communicate with a child this is what I did:

Root

in the root component:
import the 3rd level model component (as well as the second layer component that is doing the *ngFor)
in the root html
<third-level-detail-dialog-component #modal></third-level-detail-dialog-component>
<second-level-component (mySelected)="modal.showModal($event)"></second-level-component>

Second Component

In the component:
@Output() mySelected = new EventEmitter<number>()//if you are doing something like passing item ID
...
onclick(num: number){ this.mySelected.emit(num); }
in your html within the *ngFor (or wherever)
<a (click)="onclick(item.Id)" class="more"> More info... </a>

Third Component

in the component:
@ViewChild('lgModal') modal: any;
...
showModal(id: number) {
if(id != undefined){
this.getItemFromId(id); // do stuff here to populate your model
this.modal.show();
}
}

@helzgate thanks for your solution, but mine is more simple, use viewChild to take the local variable of modal and inject the grandparent component to your child component and access this variable.
Something like:

Grandparent Component

@viewChild('lgModal') modal;

Child component

constructor(private parent:GrandparentComponent){
this.parent.modal.Show(); //this will show the modal, simple example how to do.
}
And now you can access everything on your GrandParentComponent if it's declared as public.

hey to all, sample added to demo page :)

hey @BenevidesLecontes thanks! Genius!!

@wladimiravila you're welcome.

Hi Guys,

Am on RC 6

I want to implement the same scenario and i get this error

core.umd.js:3468 TypeError: Cannot read property 'show' of undefined

my code:
# modal component:

`import {Component, ViewChild} from "@angular/core";
import { ModalDirective} from 'ng2-bootstrap/ng2-bootstrap';

@Component({
selector: 'ua-add-profile-admin',
templateUrl: 'src/app/pages/user-auth/components/profile-admin/add/ua-add-profile-admin.html',
styleUrls: ['src/app/pages/user-auth/components/profile-admin/add/ua-add-profile-admin.css'],
exportAs: 'child'
})

export class UA_Add_Profile_Admin {

@ViewChild('childModal') public childModal:ModalDirective;

public showChildModal():void {
    this.childModal.show();
}

public status:Object = {
    isFirstOpen: true,
    isFirstDisabled: false,

};

public oneAtATime:boolean = true;

}`

# parent html

`




Add Admin



<div class="row">
    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
        <div class="row">
            <div class="col-md-6">
                <div class="box-body">
                    <button type="button" class="btn fnb-submit-btn" (click)="c.showChildModal()">Add Profile</button>
                    <ua-add-profile-admin #c="child"></ua-add-profile-admin>
                </div>
            </div>

            <div class="col-md-6">
                <div class="sidebar-form">
                    <div class="input-group-btn">
                        <input #gb type="text" name="q" class="form-control btn-flat" placeholder="Search..." style="background-color: white">
                    </div>
                </div>
            </div>
        </div>

        <br>

        <p-dataTable [value]="job_role" [rows]="20" [paginator]="true" [pageLinks]="3" [responsive]="true"
                     [stacked]="stacked" [globalFilter]="gb" [rowsPerPageOptions]="[5,10,20]">
            <p-column field="vin" header="Vin" [sortable]="true"></p-column>
            <p-column field="year" header="Year" [sortable]="true"></p-column>
            <p-column field="brand" header="Brand" [sortable]="true"></p-column>
            <p-column field="color" header="dadad" [sortable]="true"></p-column>
        </p-dataTable>
    </div>
    <!-- /.col -->
</div>
<!-- /.row -->

`

You need to load module , not directive

On Thu, Sep 15, 2016, 14:40 Calvin [email protected] wrote:

Hi Guys,

I want to implement the same scenario and i get this error

core.umd.js:3468 TypeError: Cannot read property 'show' of undefined

my code:
modal component:
`import {Component, ViewChild} from "@angular/core";
import { ModalDirective} from 'ng2-bootstrap/ng2-bootstrap';

@Component https://github.com/Component({
selector: 'ua-add-profile-admin',
templateUrl:
'src/app/pages/user-auth/components/profile-admin/add/ua-add-profile-admin.html',
styleUrls:
['src/app/pages/user-auth/components/profile-admin/add/ua-add-profile-admin.css'],
exportAs: 'child'
})

export class UA_Add_Profile_Admin {

@ViewChild('childModal') public childModal:ModalDirective;

public showChildModal():void {
this.childModal.show();
}

public status:Object = {
isFirstOpen: true,
isFirstDisabled: false,

};

public oneAtATime:boolean = true;

}`

parent html

`

Add Admin


`

—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/valor-software/ng2-bootstrap/issues/624#issuecomment-247305377,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABDk4zT1ZWuMvYhJfYNf7VGxRLMMhebaks5qqS6xgaJpZM4I4ofk
.

@valorkin am confused, where should I load the module.

Here is my app.module

@NgModule({ imports: [BrowserModule, Ng2BootstrapModule, DataTableModule, AccordionModule, SharedModule, ModalModule, routing], exports: [ModalModule],

Thank you problem sorted.

Replaced:

@ViewChild('childModal') public childModal:ModalDirective;

With :

@ViewChild('lgModal') public childModal:ModalDirective;

Check import section
https://github.com/valor-software/ng2-bootstrap/blob/development/demo/ng2-bootstrap-demo.module.ts

On Thu, Sep 15, 2016, 14:56 Calvin [email protected] wrote:

@valorkin https://github.com/valorkin am confused, where should I load
the module.

Here is my app.module

@NgModule({
imports: [BrowserModule,
Ng2BootstrapModule,
DataTableModule,
AccordionModule,
SharedModule,
ModalModule,
routing],
exports: [ModalModule],

—
You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub
https://github.com/valor-software/ng2-bootstrap/issues/624#issuecomment-247308113,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABDk45Fr0rpDtIaguEDLeyusoF8cpbT7ks5qqTJcgaJpZM4I4ofk
.

Hi,

I need to call the showChildModal function in another component as a method not on the html

I have similar type of use case with little change.
Let's say there is two component A and B on SAME PAGE. and both A and B adding component C as child component . Now when i click from component A it open component C modal popup as expected but when click from component B, it open same popup which was opened from Component A.(P.S. : I m using javascript to open modal popup component. not bootstrap way.)

To fix this i did little trick. I did initialise all child component (Modal popup component) with different id. and that id i m passing from respected parent component. and based on that it open popup with expected data.

But is there any other angular way to solve this rather above trick. ?
can it be solved using ng2-Bootstrap?

how in open a modal from another component (shared component modal ) and inject in my parent component with viewChild in angular 8 ? my modal is a activeModal ? and thanks for reponding

Was this page helpful?
0 / 5 - 0 ratings

Related issues

PascalHonegger picture PascalHonegger  Â·  3Comments

juanitavollmering picture juanitavollmering  Â·  3Comments

YevheniiaMazur picture YevheniiaMazur  Â·  3Comments

phmello picture phmello  Â·  3Comments

tuoitrexuquang picture tuoitrexuquang  Â·  3Comments