ngx-bootstrap modal: How to get a return value from a modal?

58,827

Solution 1

Try like this :

myexample it's working correctly. hope this will help you

home.module.ts

import { ModalModule } from 'ngx-bootstrap';

@NgModule({
    imports: [
        ModalModule.forRoot()
    ]
})

home.component.html

<button class="btn btn-primary" (click)="openConfirmDialog()">Open Confirm box
</button>

home.component.ts

import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/modal-options.class';

export class HomeComponent {
    public modalRef: BsModalRef;
    constructor(
        private homeService: HomeService,
        private modalService: BsModalService
    ) { }

    openConfirmDialog() {
        this.modalRef = this.modalService.show(HomeModalComponent);
        this.modalRef.content.onClose.subscribe(result => {
            console.log('results', result);
        })
    }
}

home-modal.component.html

<div class="alert-box">
    <div class="modal-header">
        <h4 class="modal-title">Confirm</h4>
        <button type="button" class="close" aria-label="Close" (click)="bsModalRef.hide()">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    <div class="modal-body">
        Are you sure want to delete this node?
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-secondary" (click)="onConfirm()">Yes</button>
        <button type="button" class="btn btn-secondary" (click)="onCancel()">No</button>        
    </div>
</div>

home-modal.component.ts

import { Subject } from 'rxjs/Subject';
import { BsModalRef } from 'ngx-bootstrap/modal';

export class HomeModalComponent {
    public onClose: Subject<boolean>;

    constructor(private _bsModalRef: BsModalRef) { }

    public ngOnInit(): void {
        this.onClose = new Subject();
    }

    public onConfirm(): void {
        this.onClose.next(true);
        this._bsModalRef.hide();
    }

    public onCancel(): void {
        this.onClose.next(false);
        this._bsModalRef.hide();
    }
}

Solution 2

I used the solution from @Chandru, however to return a true or false, instead of:

openConfirmDialog() {
    this.modalRef = this.modalService.show(HomeModalComponent);
    this.modalRef.content.onClose.subscribe(result => {
        console.log('results', result);
    })
}

I simply used:

openConfirmDialog() {
    this.modalRef = this.modalService.show(HomeModalComponent);
    return this.modalRef.content.onClose;
}

Solution 3

I understand that most of the answers above are completely valid, but that the main goal is be able to invoke the confirmation dialog in this way...

  async openModalConfirmation() {
    const result = await this.confirmationSvc.confirm('Confirm this...');
    if (result) {
      console.log('Yes!');
    } else {
      console.log('Oh no...');
    }
  }

Note that this is mostly syntactic sugar to simplify the use of a promise and the asynchronous stuff.

I think it's what the OP was looking for and probably can be reworked to support returning any other data type (apart from a boolean).

The rest of the code below (not including the template to keep this short), pretty straightforward..

ModalConfirmationService

import { ModalConfirmationComponent } from './component';

@Injectable()
export class ModalConfirmationService {

  constructor(private bsModalService: BsModalService) {}

  confirm(message: string): Promise<boolean> {
    const modal = this.bsModalService.show(ModalConfirmationComponent, { initialState: { message: message }});

    return new Promise<boolean>((resolve, reject) => modal.content.result.subscribe((result) => resolve(result) ));
  }
}

ModalConfirmationComponent

import { Component, Input, Output, EventEmitter} from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
import { Subject } from 'rxjs/Subject';

@Component({
  templateUrl: './component.html'
})
export class ModalConfirmationComponent {
  @Input() message: string;
  result: Subject<boolean> = new Subject<boolean>();

  constructor(public modalRef: BsModalRef) { }

  confirm(): void {
    this.result.next(true);
    this.modalRef.hide();
  }

  decline(): void {
    this.result.next(false);
    this.modalRef.hide();
  }
}

Solution 4

@ShinDarth You can add this function in your service and call this funcion whenever required.

In your Service, create this function

    openConfirmDialogBox() {
        this.modalRef = this.modalService.show(DemoModalComponent);
        this.modalRef.content.action.take(1)
            .subscribe((value) => {
                console.log(value) // here value passed on clicking ok will be printed in console. Here true will be printed if OK is clicked
                return value;
             }, (err) => {
                 return false;
        });
    }

In your demo-modal.component.ts, create an EventEmitter

 @Output() action = new EventEmitter();
 public onClickOK() {
    this.action.emit(true); //Can send your required data here instead of true
 }
 public onClickCANCEL() {
    this.action.emit(false); //Can send your required data here instead of true
 }

I hope this would help you

Solution 5

If you are using a later version of Angular you might get an error due to the location of BsModalRef that had moved:

Use this location:

import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';

rather than:

import { BsModalRef } from 'ngx-bootstrap/modal/modal-options.class';
Share:
58,827

Related videos on Youtube

Francesco Borzi
Author by

Francesco Borzi

https://github.com/FrancescoBorzi

Updated on September 23, 2020

Comments

  • Francesco Borzi
    Francesco Borzi over 3 years

    In my Angular 4 app, let's assume that I'm inside a service.

    At some point, I want to ask the user for a confirmation, currently I'm doing it with just a confirm(...) request:

    const result = confirm('Are you sure?');
    

    What if instead I would like to show an ngx-bootstrap modal with, let's say, two buttons "Yes" or "No" and obtain a similar result?


    EDIT: in my case, I solved my issue by playing with Subjects. Here you can find my solution, in case it can be useful for someone else. However that solution does not solve this question which is about returning a value from a modal, so I leave it open.

    • tdragon
      tdragon over 6 years
      Did you try something so far?
    • Francesco Borzi
      Francesco Borzi over 6 years
      in my service I'm able to show the modal using this.modalService.show(this.confirmModal) but I don't know how to receive back the result of what the user clicked in the modal
    • Chandru
      Chandru over 6 years
      @ShinDarth Just now only posted my answer.. i hope this will useful for you
  • Francesco Borzi
    Francesco Borzi over 6 years
    thanks for your answer, but how would you use it inside a service? For example inside a CanDeactivate method of a Guard that it is supposed to return true or false, without waiting?
  • Francesco Borzi
    Francesco Borzi over 6 years
    I need to replace this with a modal: canDeactivate() { return confirm( 'are you sure?' ); } }
  • RajeshKdev
    RajeshKdev over 6 years
    Great Solution :)
  • Hossein Bajan
    Hossein Bajan about 6 years
    Yeeeeeeeeeeeees, thank you so muuuch :), It's working for me.
  • tatsu
    tatsu about 6 years
    the BsModalRef path has changed from ngx-bootstrap/modal to ngx-bootstrap/modal/bs-modal-ref.service
  • Reza
    Reza about 6 years
    Great! How can I customize Are you sure want to delete this node? , I means passing it as param to openConfirmDialog
  • Jason Krs
    Jason Krs about 6 years
    How are you able to do modalService.show(HomeModalComponent) since HomeModalComponent is the export from another class and therefore in another file ?
  • tytyryty
    tytyryty almost 6 years
    @RezaRahmati, to customize message you can in home-modal.component.html change test to {{message}} and then to call show like this: const config = { message: 'Are you sure want to delete this node?'}; this.modalService.show(HomeModalComponent, { initialState: config });
  • Vinicius.Silva
    Vinicius.Silva almost 6 years
    What happen with Subject subscribed inside 'openConfirmDialog' if user clicks on backdrop?
  • HDJEMAI
    HDJEMAI almost 4 years
    We need to unsubscribe ones we go to another screen: something like: ngOnDestroy() { this.bsModalRef.content.onClose.unsubscribe(); } To avoid memory leaks
  • StNekroman Sama
    StNekroman Sama almost 4 years
    Doesn't cover dismiss by ESC key or click on backdrop.
  • Omkar
    Omkar over 2 years
    perfect solution, worked for me