angular-modal-service icon indicating copy to clipboard operation
angular-modal-service copied to clipboard

Clicking outside modal does not trigger close promise

Open Ape opened this issue 10 years ago • 10 comments

Modals can be closed by clicking outside the modal window and I want to keep that functionality. However, closing the modal this way doesn't trigger the close promise.

Should it? Closing the modal with the close icon (X) on top right corner does trigger the promise. How do I know if the modal was closed by clicking outside of it?

Ape avatar Sep 21 '15 13:09 Ape

I ended up using angular events outside of ModalService.showModal to handle this. Basically setup a attribute directive on the body tag listening for non-modal clicks... and when it gets ones, broadcasts an event to close the modal, which is handled in our controller that invokes ModalService.showModal (not the modal controller itself). The reason for this is that (for whatever reason) I couldn't get broadcasted or emitted events working on within the modal controller (it wasn't hearing them at all).

Hope it helps.

brandonburkett avatar Oct 16 '15 14:10 brandonburkett

I was having a similar problem, but was able to deal with it by watching for the Bootstrap 'hidden.bs.modal' event. Essentially:

ModalService.showModal({
              ...
    }.then(function(modal) {
        modal.element.on('hidden.bs.modal', function () {
            modal.controller.closeModal();
        });
}

MatteBailey avatar Oct 23 '15 21:10 MatteBailey

@devourment77 can you provide a fiddle?

@MatteBailey can you also provide a plunkr please. I tried to use your snippet but the snippet seems to be activated every time because the buttons also will hide the modal so the that function would be passed on every click. Also closeModal is not a function so you probably defined that one?

thank you all in advance.

tiagomsmagalhaes avatar Jan 04 '16 18:01 tiagomsmagalhaes

Yeah please provide at least something, since above ain't working for me, would love quickfix for this issue)

ghost avatar Jan 22 '16 15:01 ghost

I've added to this since my first comment in October. Hopefully the code below is helpful:

In whatever controller you're using ModalService in:

ModalService.showModal({
    templateUrl: "exampleTemplate.html",
    controller: "ExampleController",
    controllerAs: "ctrl"
}).then(function(modal) {
    modal.element.one('hidden.bs.modal', function () {
        if (!modal.controller.closed) {
            modal.controller.closeModal();
        }
    });
    modal.element.modal();
});

And then in ExampleController:

this.closed = false;

this.closeModal = function () {
    close(null, 200);
    this.closed = true;
}

And in exampleTemplate.html

<button ng-click="ctrl.closeModal()" type="button" class="btn btn-default">Cancel</button>

This addresses the issue you mentioned @tiagomsmagalhaes. If you click the "Cancel" button, this.closed (which is modal.controller.closed in your first controller) will become true, and when you catch hidden.bs.modal you won't trigger closeModal again.

Definitely a work around, but it does the job with only a few extra lines.

Make sense?

MatteBailey avatar Jan 23 '16 00:01 MatteBailey

Thx man, it's great fix indeed!!

ghost avatar Jan 23 '16 12:01 ghost

thanks for the reply @MatteBailey. Meanwhile i got it to work as described in #128. I don't know if it's more elegant than your solution. I just added the failed promise part to catch the event. I think although the hidden.bs.modal is in the failed promise section, it's being called every time which isn't so problematic but i think it's not elegant.

tiagomsmagalhaes avatar Jan 24 '16 16:01 tiagomsmagalhaes

Hi @tiagomsmagalhaes ,

If you want to run that code in the error callback of modal.close, you would do something like this:

modal.close.then(function(result) {
    $scope.yesNoResult = result ? "You said Yes" : "You said No";
}, function () {
    modal.element.on('hidden.bs.modal', function() {
        $('.modal').remove();
    });
});

I don't think this will help us though, because modal.close doesn't get rejected when a user clicks outside the modal to close it.

We generally provide an anonymous function for the promise callbacks. Since you're invoking modal.element.on(), it does indeed get run every time. I think what you have will behave the same as doing this:

modal.close.then(function(result) {
    $scope.yesNoResult = result ? "You said Yes" : "You said No";
});

modal.element.on('hidden.bs.modal', function() {
    $('.modal').remove();
});

This will definitely work for removing the modal from the DOM, but we will never resolve modal.close, which is problematic. This is the what my solution above addresses.

Let me know if I'm misunderstanding anything!

MatteBailey avatar Jan 25 '16 16:01 MatteBailey

@MatteBailey I think we should replace

$('.modal').remove(); with modal.scope.$destroy();

It will completely removed all the watchers in modal.

Hope it helps :)

brianalexandro avatar Aug 24 '17 02:08 brianalexandro

Please look at below for the perfect and easiest solution http://magentocodes.blogspot.in/2017/10/how-to-close-modal-popup-clicking.html

rohitgoel avatar Oct 12 '17 04:10 rohitgoel