Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Modal dialog closes when mouse button is pressed over the dialog window but released outside the window #5810

Open
maxkoretskyi opened this issue Apr 15, 2016 · 12 comments · May be fixed by #6640

Comments

@maxkoretskyi
Copy link

maxkoretskyi commented Apr 15, 2016

Bug description:

STR:

  1. Hover over the modal dialog
  2. Press left mouse button down
  3. Move mouse outside the modal window
  4. Release the button

ER:
Modal dialog is closed

AR:
Modal dialog should not be closed since click actually occurred on the dialog. Closing of the dialog especially annoying when selecting a text on the dialog and accidentally move the mouse outside of the dialog.
video.zip

Clarification:
This is clearly a bug. I want a dialog to close on backdrop click (so I don't want to use static), but I don't want it to close when click is initiated on a dialog (for example, during text selection as shown in the attached video).

There is a simple fix for that issue and I have created a pull request.
video.zip

Link to minimally-working plunker that reproduces the issue:

http://angular-ui.github.io/bootstrap/
section Modal (ui.bootstrap.modal) -> click on the Open me button

Version of Angular, UIBS, and Bootstrap

Angular
1.5.3

UIBS:
1.3.2

Bootstrap:
3.3.6

@icfantv
Copy link
Contributor

icfantv commented Apr 15, 2016

@MaximusK, let's take the emotion out of equation, please. i'm all for reasoned passion, but let's please be careful of the content and tone. thanks.

@maxkoretskyi
Copy link
Author

maxkoretskyi commented Apr 15, 2016

hey, I didn't feel I got emotional when writing this. if it appears so from the text, sorry, I can edit it, just let me know what exactly seems inappropriate

@wesleycho
Copy link
Contributor

The explanation given is incorrect - the click event does fire on the modal window, as demonstrated here. Notice that the raw DOM addEventListener method triggers the click event, so this is clearly the browser behavior.

The question lies as to whether this is worth changing the behavior at all. It looks like Bootstrap has logic for this situation, as seen here, so I guess I'm open to changing this, although this is fairly minor.

@maxkoretskyi
Copy link
Author

Ok, yeah, I think you understand the problem now. I tried to submit pull request with changes, but it failed on travis built. Do you want me to submit those changes again or you'll find the way to implement it yourself?

@alexandernst
Copy link

I just hit this issue. Is there a fix or a workaround?

@webenji
Copy link

webenji commented Aug 16, 2016

I also came across this issue, which we found especially problematic with range sliders inside modals. The users would click on the range slider, drag it past the modal window, and release it, causing the entire modal to close. Very unexpected behavior to say the least.

Although I think this should officially be added into the code, you can use maximusk pull request to change the code yourself.

@wesleycho
Copy link
Contributor

The code change from #5911 will be the one added, just need tweaks in the tests - one absolutely must have this behavior asap for a strange reason, one can merge that into a fork.

If they aren't changed sometime in the next few weeks, I'll probably make the necessary changes locally and merge it.

@iget-esoares
Copy link

iget-esoares commented Mar 14, 2017

Any fix for this issue? Or workaround? Thats painfull for my application that have a google map on the modal.

User try to drag the map and closes the modal suddenly.

@ernespa
Copy link

ernespa commented May 11, 2017

I think this workaround does the job

$scope.$watch(function(){return $('.modal').length;},function(val){//everytime the number of modals changes
    if(val>0){
        $modalStack.getTop().value.backdrop = 'static';//disable default close behaviour
        $('.modal').on('mousedown', function(e){
            if(e.which === 1){//left click
                $modalStack.getTop().key.dismiss();//close top modal when clicking anywhere, you can close all modals using $modalStack.dismissAll() instead
            }
        });
        $('.modal-content').on('mousedown', function(e){
            e.stopPropagation();//avoid closing the modal when clicking its body
        });
    }
});

Don't forget to inject $modalStack in your controller.

@nickgrealy
Copy link

nickgrealy commented Sep 1, 2017

@ernespa - thanks! I needed to make a few tweaks... (import jquery and inject $uibModalStack)

var $ = require('jquery');

...
.controller('UpdateProfilePictureController', function($uibModalStack, ...) {
    $scope.$watch(function() {
        return $('.modal').length;
    }, function(val) { // everytime the number of modals changes
        if (val > 0) {
            $uibModalStack.getTop().value.backdrop = 'static'; // disable default close behaviour
            $('.modal').on('mousedown', function(e) {
                if (e.which === 1) { // left click
                    $uibModalStack.getTop().key.dismiss(); // close top modal when clicking anywhere, you can close all modals using $modalStack.dismissAll() instead
                }
            });
            $('.modal-content').on('mousedown', function(e) {
                e.stopPropagation(); // avoid closing the modal when clicking its body
            });
        }
    });
});

TheSharpieOne pushed a commit to reactstrap/reactstrap that referenced this issue May 29, 2018
Modal dialog closes when mouse button is pressed over the dialog window but released outside the window.

See angular-ui/bootstrap#5810 for video. Pull request is based on code changes made in that project.
@Eugeny
Copy link

Eugeny commented Mar 25, 2019

Non-jquery version:

$rootScope.$watch(() => document.querySelectorAll('.modal').length, val => { // everytime the number of modals changes
  if (val > 0) {
    $uibModalStack.getTop().value.backdrop = 'static'
  }

  for (let modal of document.querySelectorAll('.modal')) {
    modal.addEventListener('mousedown', e => {
      if (e.which === 1) {
        $uibModalStack.getTop().key.dismiss()
      }
    })
    modal.querySelector('.modal-content').addEventListener('mousedown', e => {
      e.stopPropagation()
    })
  }
})

@Walhfort
Copy link

Non-jquery version:

$rootScope.$watch(() => document.querySelectorAll('.modal').length, val => { // everytime the number of modals changes
  if (val > 0) {
    $uibModalStack.getTop().value.backdrop = 'static'
  }

  for (let modal of document.querySelectorAll('.modal')) {
    modal.addEventListener('mousedown', e => {
      if (e.which === 1) {
        $uibModalStack.getTop().key.dismiss()
      }
    })
    modal.querySelector('.modal-content').addEventListener('mousedown', e => {
      e.stopPropagation()
    })
  }
})

I had a problem with where your fix would override the modal backdrop parameter, resulting in originaly 'static' modals not behaving as such.
Here is my fix for your fix :

$rootScope.$watch(() => document.querySelectorAll('.modal').length, val => { // everytime the number of modals changes
  for (let modal of document.querySelectorAll('.modal')) {
    if ($uibModalStack.getTop().value.backdrop !== 'static') { // Testing if the modal is supposed to be static before attaching the event
      modal.addEventListener('mousedown', e => {
        if (e.which === 1) {
          $uibModalStack.getTop().key.dismiss()
        }
      })
      modal.querySelector('.modal-content').addEventListener('mousedown', e => {
        e.stopPropagation()
      })
    }
  }
  if (val > 0) {
    $uibModalStack.getTop().value.backdrop = 'static'
  }
})

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants