Dismiss ngb-modal outside modal controller - javascript

I've created a component with the content of a modal that I want to display on other multiple components.
modal.component.html:
<div class="modal-header">
<h4 class="modal-title"></h4>
<button type="button" class="close" aria-label="Close" (click)="dismissModal()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">...</div>
modal.component.js:
export class ModalComponent implements OnInit {
constructor(
private modal: NgbActiveModal
) { }
dismissModal() {
this.modal.dismiss();
}
}
And I'm calling this content in other parts of my site, such us:
header.component.html:
<button (click)="openModal(myModal)">
Open Modal
</button>
<ng-template #myModal let-modal>
<app-modal-content></app-modal-content>
</ng-template>
header.component.ts:
openModal(content: string) {
this.modalRef = this.modalService.openModal(content, { centered: true });
}
The modal shows up correctly, but when I try to dismiss the modal by pressing X it does not work, because the modal reference is in the header component. How could I dismiss the modal if I'm opening it from other component?

The modal.component.ts file should inject the NgbActiveModal service in order to close the modal.
In the modal.component.ts file constructor:-
import { NgbActiveModal, NgbModal } from '#ng-bootstrap/ng-bootstrap';
export class ModalComponent {
constructor(public modal: NgbActiveModal) {}
}

Related

Detect Click event inside ngx bootstrap modal

I have implemented a ngx bootstrap modal following this guide - https://valor-software.com/ngx-bootstrap/#/modals#bs-modal-service. but when the modal is opened how can i detect any click events inside the modal body. I have the below code in my app component.
I have tried this with viewChild but when I am clicking inside the modal after it is opened always returns undefined.
App Component HTML -
<button type="button" class="btn btn-primary" (click)="openModal(template)">Create template modal</button>
<ng-template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">Modal</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" #modalBody>
This is a modal.
</div>
</ng-template>
App Component ts -
import { Component, TemplateRef, OnInit, ViewChild, ElementRef } from '#angular/core';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
host: {
'(document:click)': 'closemodal($event)'
}
})
export class AppComponent mplements OnInit{
#ViewChild('modalBody', { static : false}) modalBody : ElementRef;
modalRef: BsModalRef;
constructor(private modalService: BsModalService) {}
ngOnInit() {}
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
closemodal(event : any) {
if (!this.modalBody.nativeElement.contains(event.target)){
console.log('clicked in the modal')
}
}
}
I am not sure what is the issue with binding a event handler directly in the modal body DOM. Try the following
Template
<button style="margin: 10px" type="button" class="btn btn-success" (click)="openModal(template)">Create template modal</button>
<ng-template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">Modal</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<span style="cursor: pointer" (mouseup)="textClick($event)">Some sample text</span>
<br><br>
<button type="button" class="btn btn-primary" (click)="onClick($event)">Click me</button>
</div>
</ng-template>
Controller
export class AppComponent {
modalRef: BsModalRef;
constructor(private modalService: BsModalService) {}
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
}
textClick(event: any) {
console.log('text clicked inside modal body');
}
onClick(event: any) {
console.log('button clicked inside modal body');
}
}
Working example: Stackblitz

Angular 6 modal opening on same page not in popup

I am have an angular 6 project that includes a toolbar on the top of the page with a "Sign In" button. When I click on this button, I want a modal dialog to appear.
However, I ran there are two issues illustrated in the screenshot below. The first is when I load the page, both modals (outlined in red) are loaded. They should only appear if the appropriate button is clicked.
Stackblitz project is at below link:
https://stackblitz.com/github/eugene01a/online-exam/tree/master/frontend
The second issue is why are they not appearing in their own dialog popup?
import {
Component,
OnInit
} from '#angular/core';
import {
ModalService
} from "./_services";
import './_content/app.less';
import './_content/modal.less';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
authenticated = false;
constructor(private modalService: ModalService) {}
ngOnInit() {}
openModal(id: string) {
this.modalService.open(id);
}
closeModal(id: string) {
this.modalService.close(id);
}
}
<!-- main app container -->
<mat-toolbar color="primary" class="mat-elevation-z10">
<button mat-button>Online Exams</button>
<button mat-button>About</button>
<!-- This fills the remaining space of the current row -->
<span class="fill-remaining-space"></span>
<button mat-button (click)="openModal('signin-modal')" *ngIf="!authenticated">Sign In</button>
<button mat-button (click)="openModal('signout-modal')" *ngIf="authenticated">Sign Out</button>
</mat-toolbar>
<div class="view-container">
<router-outlet></router-outlet>
</div>
<jw-modal id="signin-modal">
<h1>Sign in button clicked</h1>
<button (click)="closeModal('signin-modal');">Close</button>
</jw-modal>
<jw-modal id="signout-modal">
<h1>Sign Out button clicked</h1>
<button (click)="closeModal('signout-modal');">Close</button>
</jw-modal>

How to close bootstrap 4 model by calling a function in typescript

I am using bootstrap 4 modal followed by the example
Below is the template code:
<div class="container">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
Open
</button>
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Modal Heading</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<!-- Modal body -->
<div class="modal-body">
Modal body..
</div>
<button type="button" class="btn btn-danger" (click)="save()">Save</button>
</div>
</div>
</div>
</div>
Here on clicking the open button i am opening dialog window,On clicking save button i will call save() method.In .ts i have written some conditions inside save method like this:
save(){
if(condition){
......don't close the modal....
} else{
......close the modal....
}
}
How can i close the modal by calling the save() method in typescript?
Stackblitz DEMO
The proper way to do this in Angular/Typescript is to use ViewChild.
First import ViewChild :
import { ViewChild } from '#angular/core';
Add this line in your component, with the selector of your choice :
#ViewChild('myModalClose') modalClose;
Add the tag myModalClose in your html (here we target the close button) :
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" #myModalClose class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
...
In your save() method :
this.modalClose.nativeElement.click();
Working Stackblitz
I have another solution without trick on close button.
First step you need install jquery and bootstrap by npm command.
Second you need add declare var $ : any; in component (important step)
And use can use $('#myModal').modal('hide'); on onSave() method
Demo https://stackblitz.com/edit/angular-model-bootstrap-close?file=src/app/app.component.ts
You can use ng-bootstrap alternatively to control all this in your component class.
ng-bootstrap
In typescript component code you need to inject NgbActiveModal in the constructor like this:
constructor(public activeModal: NgbActiveModal){}
and then in save method, you can just close it:
save(){
if(condition){
......don't close the modal....
} else{
this.activeModal.close();
}
}
Use Ngx bootstrap https://valor-software.com/ngx-bootstrap/#/modals
here is the common component for ngx bootstap modal.
<!-- Contains insides of a host element e.g. button text or link text -->
<ng-content></ng-content>
<!-- Dialog box content -->
<ng-template #modalWrapper>
<!-- Header template -->
<div class="modal-header">
<h3 class="modal-title pull-left">{{ modalTitle }}</h3>
<button type="button" class="close pull-right" aria-label="Close" (click)="closeModal()">
<span aria-hidden="true">×</span>
</button>
</div>
<!-- Body template that consist of provided template reference content -->
<div class="modal-body">
<ng-container [ngTemplateOutlet]="modalContent"></ng-container>
</div>
</ng-template>
Component.ts
export class AppModalComponent implements OnInit, OnChanges {
/** Template Reference that is displayed as part of dialog box content */
#Input('app-modal') public modalContent: TemplateRef<any>;
/** Title of the dialog box */
#Input() public modalTitle: string = '';
/** Defines if modal is open */
#Input() public isOpenByDefault: boolean = false;
/** Modal reference */
public modalRef: BsModalRef;
/** Content config object */
#Input() public config: ModalOptions = {};
/** Event on modal open */
#Output() public open = new EventEmitter<void>();
/** Event on modal close */
#Output() public close = new EventEmitter<void>();
/** Wrapper template reference */
#ViewChild('modalWrapper') public content: TemplateRef<any>;
/** Injects modalService to manipulate modals */
constructor(private modalService: BsModalService) { }
public ngOnChanges(changes: SimpleChanges) {
if (changes.config) {
this.modalService.config = changes.config.currentValue;
}
}
public ngOnInit(): void {
this.isOpenByDefault ? this.openModal() : this.closeModal();
}
/** On click of host element opens a modal with provided modal content */
#HostListener('click')
public openModal(): void {
this.modalRef = this.modalService.show(this.content, this.config);
this.open.emit();
}
/** On click of close button closes the modal */
public closeModal(): void {
if (this.modalRef) {
this.modalRef.hide();
this.close.emit();
}
}
}
Usage :
<button [app-modal]="template" modalTitle="Modal Title" [isOpenByDefault]="false" #modalRef>Open modal</button>
<ng-template #template>
<h4>Hello world</h4>
</ng-template>

Modal doesn't appear correctly angular 4

I am using ng-bootstrap Here try to do a modal sample ,but when i click on open modal it doesn't appear although it exists inside the DOM.
my angular core version :4.0.0 , #ng-bootstrap/ng-bootstrap :1.0.0-alpha.29, bootstrap :3.3.7
test-modal.component.html
<div class="modal-header">
<h4 class="modal-title">Hi there!</h4>
<button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Hello, {{name}}!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" (click)="activeModal.close('Close click')">Close</button>
</div>
test-modal.component.ts
import {Component,Input} from '#angular/core';
import {NgbModal,NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
#Component({
selector: 'app-test-modal',
templateUrl: './test-modal.component.html',
styleUrls: ['./test-modal.component.css']
})
export class TestModalComponent {
#Input() name;
constructor(public activeModal: NgbActiveModal) {}
}
the open function in app.component.ts with the constructor
constructor(private modalService: NgbModal) {}
open() {
const modalRef = this.modalService.open(TestModalComponent);
}
the button inside app.component.html
<button class="btn btn-lg btn-outline-primary" (click)="open()">Launch demo modal</button>
I think the problem might be your bootstrap version bootstrap :3.3.7, when I got to the homepage it says it is for Bootstrap 4 (it also says bootstrap 4 on the get started).
And testing over here in a Angular 4 + Bootstrap 4 project I got it working
In package.json
"#ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.29",
"bootstrap": "^4.0.0-alpha.6",
In my module
imports: [
NgbModule.forRoot(), ...
],
entryComponents: [ModalTemplateComponent],
In a component:
modal: NgbModalRef;
constructor(private modalService: NgbModal) { }
async open() {
this.modal = this.modalService.open(ModalTemplateComponent);
const result = await this.modal.result;
console.log(result);
}

Ng-bootstrap modal not showing

My goal is to open a modal in angular when I press a button. I decided to use ng-bootstrap for this. I went to their website and decided to copy paste the default modal code into my application.
The button is showing and when I click it, the screen moves a little bit, but there is no modal to be seen. When I click the button a second time I get a feedback Dismissed by clicking on a backdrop. The console shows me no errors.
Does anyone know how to fix this?
image of what the webpage looks like
homepage HTML file: the ng-template is the modal
<div class="col-md-8 col-md-offset-2">
<h5>Welcome to MovieMeter! <span *ngIf="isLoggedIn"> You are logged in as {{fullName}}</span></h5>
<br>
<ng-template #content let-c="close" let-d="dismiss">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
<button type="button" class="close" aria-label="Close" (click)="d('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>One fine body…</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-dark" (click)="c('Close click')">Close</button>
</div>
</ng-template>
<button class="btn btn-lg btn-outline-primary" (click)="open(content)">Launch demo modal</button>
<hr>
<pre>{{closeResult}}</pre>
<h3>Trailers:</h3>
<hr>
<ul>
<li *ngFor="let trailer of trailers">
<img src="{{trailer.body.items[0].snippet.thumbnails.high.url}}" alt="nope">
<div class="trailerTitle"><h5>{{trailer.movie.title}}</h5></div>
</li>
</ul>
<app-cinema-featured></app-cinema-featured>
</div>
Home.component.ts
import {Component, OnInit} from "#angular/core";
import {AuthService} from "../auth/auth.service";
import {MovieService} from "../movie/movie.service";
import {NgbModal, ModalDismissReasons} from '#ng-bootstrap/ng-bootstrap';
#Component({
styleUrls: ['./home.component.css'],
selector: 'app-home',
templateUrl: './home.component.html'
})
export class HomeComponent implements OnInit {
isLoggedIn:Boolean;
fullName;
trailers;
closeResult: string;
constructor(private modalService:NgbModal, private authService: AuthService, private movieService: MovieService){}
ngOnInit(){
if (localStorage.getItem('token') !== null || undefined){
this.isLoggedIn = true;
this.fullName = localStorage.getItem('fullName');
}
// get the thumbnails and links of the three most recent movie trailers via the youtube API
this.movieService.getTrailers()
.subscribe(trailers => {
this.trailers = trailers.result;
console.log(this.trailers);
})
}
open(content) {
this.modalService.open(content).result.then((result) => {
this.closeResult = `Closed with: ${result}`;
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
}
Update: this are the elements in the console after I clicked the button. The ng backdrop and ng-modal are showing, but cannot be seen.
After trying a lot of things I discovered that I needed bootstrap 4 instead of bootstrap 3.
Try to use #ViewChild to select the modal in your component code:
HTML
<button class="btn btn-lg btn-outline-primary" (click)="open()">Launch demo modal</button>
TS
#ViewChild("content") content: NgbModal;
open() {
this.modalService.open(this.content).result.then((result) => {
this.closeResult = `Closed with: ${result}`;
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
//1. The modal component has to be registered in entryComponents (angualr 8 and prev)
entryComponents: [
YourModalComponent
],
providers: [
...]
//2. also the model directly inputted in the open:
openConfirmUpdateModal() {
this.modalService.open( YourModalComponent);
}

Categories