Francesco Borzi
Francesco Borzi

Reputation: 61724

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

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.

Upvotes: 50

Views: 73949

Answers (9)

Eugene
Eugene

Reputation: 119

Try this!!!! Create modal options with a yes function and a no function in the options. Receive args as @Input...

import { Component, OnInit, Input } from '@angular/core';
import { BsModalRef } from 'ngx-bootstrap/modal';

@Component({
    selector: 'confirm-box',
    templateUrl: './confirm-box.component.html',
    styleUrls: ['./confirm-box.component.css']
})
export class ConfirmBoxComponent implements OnInit {
    private _args: any;

    public get args(): any {
        return this._args;
    }

    @Input()
    public set args(value: any) {
        this._args = value;
    }

    constructor(private activeModal: BsModalRef) {
    }

    ngOnInit(): void {
    }

    public no(): void {
        this.args.noFunction();
        this.activeModal.hide();
    }

    public yes(): void {
        this.args.yesFunction();
        this.activeModal.hide();
    }
}

And then the component or service that launches the dialog:

import { BsModalService, BsModalRef, ModalOptions } from 'ngx-bootstrap/modal';
import { ConfirmBoxComponent } from '../../dialogs/confirm-box/confirm-box.component';

export class AreYouSure {    
    private activeModal: BsModalRef;

    constructor(private modalService: BsModalService) {
          //Wait five seconds before launching the confirmbox
          setTimeout(()=>{
             this.tryLaunchConfirm();
          }, 5000);
    }
    private tryLaunchConfirm(): void {
        const config: ModalOptions = {
            initialState: {
                args: {
                    title: "Confirm This",
                    message: "Are you really sure???",
                    yesFunction: () => { console.log("YES!!!! was clicked."); },
                    noFunction: () => { console.log("NO!!!! was clicked."); }
                }
            }
        }
        this.activeModal = this.modalService.show(ConfirmBoxComponent, config);

    }
}


Upvotes: 1

Chandru
Chandru

Reputation: 11184

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();
    }
}

Upvotes: 140

Krystian
Krystian

Reputation: 2290

I do not know if that suits you, but I used a service with Subject. In parent component it is enough to subscribe and unsubscribe, in modal component, when user clicks confirm button, then just emit value using next.

I'm sorry for not presenting a full example, but pseudocode below should present the idea.

Service:

export class SomeService{
    yourSubject: new Subject<string>();
}

Parent component:

...
ngOnInit(){
    this.bsModalRef = this.someService.yourSubject.subscribe ( val => ...);
}
ngOnDestroy(){
    this.bsModalRef.unsubscribe();
}
...

Modal component:

...
onSaveAction(){
    this.someService.yourSubject.next(val);
}
...

Ps. of course you need to provide service in proper place and inject it into components :-)

Upvotes: 1

francoiscx
francoiscx

Reputation: 336

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';

Upvotes: 1

MHS
MHS

Reputation: 931

Try this:

home.component.ts

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

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

 openConfirmDialog() {
    this.modalRef = this.modalService.show(HomeModalComponent);

    this.modalRef.content.onClose = new Subject<boolean>();

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

and

home-modal.component.ts

import { BsModalRef } from 'ngx-bootstrap/modal';
export class HomeModalComponent {

 constructor(private bsModalRef: BsModalRef) {

 }

 public ngOnInit(): void {
 }

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

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

Upvotes: 1

Vijay Kesanupalli
Vijay Kesanupalli

Reputation: 155

Try with below option which is working for me. callbackOnModelWindowClose is the return value.

@Output() callbackOnModelWindowClose: EventEmitter<null> = new EventEmitter();

const initialState = {
          isModelWindowView: true, bodyStyle: 'row', gridDataList: this.scheduleList
        };

this.modalRef = this.modalService.show(YourComponent,
          Object.assign({}, this.modalConfig, { class: 'modal-dialog-centered', initialState });

this.modalRef.content.callbackOnModelWindowClose.take(1).subscribe(() => {
            your code here..
          });

Upvotes: 0

agascon
agascon

Reputation: 785

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();
  }
}

Upvotes: 5

khush
khush

Reputation: 2801

@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

Upvotes: 4

Chris Halcrow
Chris Halcrow

Reputation: 31940

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;
}

Upvotes: 10

Related Questions