Sometimes when I want to quickly select the entire text of an input (within a modal), I begin selecting from the end of the text and move the mouse to the left until the entire text is selected and then I release.
Sometimes this release will occur outside the modal because the mouse movement is fast.
Picture describing the movement:
The problem is that the modal is closed when I release outside.
Question: how can I prevent the modal from closing when releasing outside?
I'm okay with the modal being closed with a click outside. But not okay with the release event.
I'm using:
angularjs 1.5.8
angular-bootstrap 2.5.0 (aka bootstrap-ui)
bootstrap 3.3.7 (only css!!! not js, because js is provided by the above)
Update:
I've created a plunkr and a GIF:
https://plnkr.co/edit/mxDLAdnrQ4p0KKyw?p=info
<div class="modal-body">
<div class="form-group">
<label for="">Foo</label>
<input type="text" class="form-control input-sm" ng-model="foo">
<p>Do this: select the text from right to left and release the mouse outside the modal.</p>
</div>
</div>
GIF:
Update 2
I have new information! This started happening after the last Goole Chrome update! I tried with another computer that had the previous version of Chrome and the modal doesn't close.
//prevent modal close when click starts in modal and ends on backdrop
$(document).on('mousedown', '.modal', function(e){
window.clickStartedInModal = $(e.target).is('.modal-dialog *');
});
$(document).on('mouseup', '.modal', function(e){
if(!$(e.target).is('.modal-dialog *') && window.clickStartedInModal) {
window.preventModalClose = true;
}
});
$("#modal").on("hide.bs.modal", function (e) {
if(window.preventModalClose){
window.preventModalClose = false;
return false;
}
});
The original repository has been archived and no contributions are accepted.
I forked a version and added my fixes for those who are interested:
https://github.com/peteriman/bootstrap
The comparison below:
https://github.com/angular-ui/bootstrap/compare/master...peteriman:modal-patch
= // moved from template to fix issue #2280
- element.on('click', scope.close);
+ var ignoreClick = false;
+ element.on('mousedown', function(evt1) {
+ element.one('mouseup', function(evt2) {
+ if (evt1.target !== evt2.target)
+ ignoreClick = true;
+ });
+ });
+ element.on('click', function(){
+ if (ignoreClick) ignoreClick = false;
+ else scope.close.apply(this, arguments);
+ });
As mousedown and mouseup events trigger before click event, the code checks if mousedown and mouseup are on the same element. If on different elements, it sets ignoreClick=true for the click event to not trigger.
Maintains backward compatibility for click event for existing codes that calls element.click() programmatically.
Original problem:
https://plnkr.co/edit/mxDLAdnrQ4p0KKyw?p=info&preview
Solution by me: (plkr, modal.js, line 103-114)
https://plnkr.co/edit/V42G9NcTUnH9n9M4?p=info&preview
I updated only the code referring to "Modal.js" in bootstrap.js and bootstrap.min.js
Corrected version:
* Bootstrap: modal.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#modals
bootstrap.js print
Yes, this started happening again after the last Goole Chrome update Version 74.0.3729.169, is this a bug with Chrome we can't fix and that we'll just have to wait for a Chrome update for it to be resolved?
or a bootstrap maintainer will update the code for fixing this?
Issue url: https://github.com/twbs/bootstrap/issues/28844
This problem is not recent is already mentioned on github
https://github.com/angular-ui/bootstrap/issues/5810
the following solution works very well with small improvements if necessary.
$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'
}
})
Another solution on the same principle that keeps the draggrable footer and header of the modal
$rootScope.$watch(function () {
return $document.find('.modal').length;
}, function (val) {
if(openedWindows.top() ) {
var modal = $document.find('.modal');
angular.forEach(modal, function(value) {
if ($modalStack.getTop().value.backdrop !== 'static') {
value.addEventListener('mousedown', function (e) {
if (value === e.target && e.which === 1 && openedWindows.top()) {
$modalStack.getTop().key.dismiss();
}
});
}
});
if (val>0) {
$modalStack.getTop().value.backdrop = 'static';
}
}
});
I'm using Bootstrap v3.0.0 and ran into the same problem. In the end, I had to change a click event to a mousedown event.
In my bootstrap.js file, under the modal.js section, I changed this.$element.on('click.dismiss.modal', $.proxy(function (e) to this.$element.on('mousedown.dismiss.modal', $.proxy(function (e). and everything appears to be working. You may also have to change this in the bootstrap.min.js file.
Note, this will immediately close the modal on mouse down of backdrop so if for some reason you want a user to be able to click down on the backdrop, then drag the mouse and release on the modal, this will not work.
Have you tried using backdrop: 'static'. I think that should do the trick. It is present in the documentation here
Add css padding around modal window and resize it larger. Click outside still works but releasing mouse while dragging over the edge won't close it.
I had a similar situation with range slider. leaving click during slide outside the modal closes it. so I removed data-toggle="modal" and data-target="#mymodal" and added a click event with extra parameters
jQuery('button#modal_toggler').click(function(){
jQuery('#myModal').modal({
backdrop: 'static',
keyboard: false
})
})
backdrop to disable modal close on clicking outside
keyboard this is for my scenario, to disable keyboard entry for closing modal
I have figured out different way to solve the problem, idk if it will cause a problem later but anyway it works, so basically, I put modal-dialog to another <div> object (I call it modal-helper) and then put it to modal. The modal-helper element width and height are inherited (100%) as default but there is small space on top so you can use some margin and padding to close it.
<div class="modal fade" id="login-modal" tabindex="-1" aria-labelledby="loginModalLabel" style="display: none;" aria-hidden="true">
<div id="modal-helper" style="pointer-events: auto;">
<div class="modal-dialog">
...
</div>
</div>
</div>
Then I have used some JS to hide modal when modal-helper (as backdrop) is clicked (by the 'clicked' I mean when pointerup event triggered after pointerdown event on modal-helper).
The code below sets the value of isPointerDownToModalHelper true when pointerdown event triggered on modal-helper, then when the pointerup event triggered on any object it hides the modal and sets the value of isPointerDownToModalHelper back to false:
var login_modal_helper = document.getElementById('modal-helper')
var isPointerDownToModalHelper = false;
addEventListener('pointerdown', (event) => {
var objectID = event['path']['0']['id'];
if (objectID === login_modal_helper.id) { // if pointer was over modal-helper
isPointerDownToModalHelper = true;
}
});
addEventListener('pointerup', (event) => {
if (isPointerDownToModalHelper === true) {
isPointerDownToModalHelper = false;
$('#login-modal').modal('hide'); // hide the modal
}
});
It seems to work fine for now, I hope it can help someone :).
I have done a lot of research on this, and can not figure out the best way to solve this. I am trying to prevent a user from clicking multiple times on a custom button in a VF page. When that is done, they invoke the method related to the button multiple times. I saw quite a few posts with different solutions, but most of them are on posts from 5-10 years ago.
<script src="//ajax.googleapis.com/ajax/libs/jquery/latest/jquery.js"></script>
<script>
function buttonsEnabled(enabled) {
// retrieve all of the buttons or links on the page
// with the css class of btn
var $buttons = jQuery('.btn');
if (enabled === false) {
// add the btnDisabled class to give it the look of being disabled
// add the disabled attribute to actually disable interactability
$buttons.toggleClass('btnDisabled', true).attr('disabled', 'disabled');
} else {
// remove the css class and the disabled attribute
$buttons.toggleClass('btnDisabled', false).attr('disabled', null);
}
}
function doSomeWork() {
// first, call the action function to post the form
doSomeWorkActionFunction();
// second, disable the buttons
buttonsEnabled(false);
// third, return false to prevent the click from
// posting the form a second time
return false;
}
</script>
<apex:form>
<apex:actionFunction name="doSomeWorkActionFunction"
action="{!yourControllerMethod}"
oncomplete="buttonsEnabled(true);"
rerender="whateverYouNeedToRerender"></apex:actionFunction>
<apex:commandLink action="{!yourControllerMethod}"
value="Your Text Here"
id="theCommandLink"
onclick="return doSomeWork();" />
</apex:form>
Got a problem, here the situation:
I want to uncheck the first checkbox when I uncheck the second checkbox.
Let say, by default both checkbox are checked. When I click second checkbox, I want the first checkbox to uncheck also.
HTML:
<ion-checkbox ng-model="firstCheckbox">First Checkbox</ion-checkbox>
<ion-checkbox ng-model="secondCheckbox" ng-change="uncheckFirstCheckbox(secondCheckbox)">Second Checkbox</ion-checkbox>
JS:
$scope.uncheckFirstCheckbox = function(secondCheckbox) {
if(secondCheckbox.checked === false) {
$scope.firstCheckbox = false;
};
};
The $scope.firstCheckbox turn false but it remain uncheck in HTML.
May I know where could be the problem?
You're trying to access secondCheckbox.checked property but secondCheckbox is already false. You should be only checking secondCheckbox for a false value. Use if(!secondCheckbox) instead for the condition.
Here is a working fiddle of your code.
HTML
<ion-checkbox ng-model="firstCheckbox">First Checkbox</ion-checkbox>
<ion-checkbox ng-model="secondCheckbox" ng-change="uncheckFirstCheckbox(secondCheckbox)">Second Checkbox</ion-checkbox>
JS
$scope.uncheckFirstCheckbox = function(secondCheckbox) {
if (!secondCheckbox) {
$scope.firstCheckbox = false;
};
};
I'm trying to enable and disable the button using some condition
I am able to disable the button using $scope.isDisabled = true; , but can't enable the button
Here is my code
HTML file
<input type="submit" value="Continue" ng-model="isDisabled" ng-disabled="isDisabled">
Controller JS file
$scope.isDisabled = true; // here the button disabled (for me)
if (count >= 3) { // it's always true
$scope.isDisabled = false; // try to enable the button here
}
Do not use $scope.apply. That is not what it is meant for.
The button does not need to be bound to a model, try removing the ng-model from the button.
Also, if it is an input type of "submit" and you are not inside an ng-form, that might
cause a postback and you might lose your state.
Here is a plunk that shows it working - i made some assumptions to get the plunk going. added an extra button that triggered the count increments.
http://plnkr.co/edit/QGYMqGHCKUoDGaY9WYhj?p=preview
Creating a calculator-like dialog, I noticed that quickly clicking on a button in IE will not fire the click event twice (Chrome/FF work as expected), but rather throws the click event, then a double-click event. Experimenting with some simple code, I essentially want to duplicate this behavior:
<script language=javascript>
function minus(num)
{
var i = document.getElementById('0001');
if (i.value > 1)
{
i.value -= num;
return true;
}
}
</script>
<input type="button" onclick="minus(1);" ondblclick="minus(1);" value="minus">
<input type="text" id="0001" name="0001" value=10>
I need to do this in ExtJS 3.1, but my efforts have been stymied. Here is the code I have tried:
Button btn = new Ext.Button(new ButtonConfig()
.text(text)
.tooltip(tooltip)
.tooltipType("title")
.scope(this)
.handler(delgateFunction)
.x(x)
.y(y)
.tabIndex(_tabIndex++)
.width(width).height(height)
.ToDictionary());
btn.addListener("mouseenter", new EventHandler(mouseHandler));
btn.addListener("mouseover", new EventHandler(mouseHandler));
btn.addListener("mouseout", new EventHandler(mouseLeave));
if (Ext.isIE)
{
//btn.on("dblclick", new EventHandler(DoubleClick));
//btn.addListener("dblclick", new EventHandler(DoubleClick));
//btn.addListener("ondblclick", new EventHandler(DoubleClick));
}
None of those three lines seemed to work. Any suggestions?
try the following after the button is rendered:
btn.el.on("dblclick", new EventHandler(DoubleClick));
Ext.Button itself hasn't the "dblclick" event (check the api) while its underlying el(Ext.Element) has.
Complete Sample:
new Ext.Button({id:'btn', text:'dblclick', renderTo:Ext.getBody() });
Ext.getCmp('btn').el.on('dblclick', function(){alert('db click');});
Mr. Zhu led me to the correct answer:
Events.AddEvent(_zeroBtn.getEl().dom, "dblclick", DoubleClickZero);