How can I execute a function when a disabled checkbox is clicked? - javascript

I have a checkbox on a page that is disabled until some criteria is met.
In an effort to give the user some information, I'd like to have a 'tool tip' display when the user tries to click on the disabled checkbox. The problem I'm having is that I can't get the onClick event to trigger on the checkbox.
Here is some sample code:
<script>
function notify() {
alert("Hello");
}
</script>
<input type="checkbox" onclick="notify();" id="thisOneWorks"/>
<input type="checkbox" onclick="notify();" id="thisOneDoesnt" disabled/>
When the checkbox is enabled, the onClick event will fire.
When the checkbox is disabled, the onClick event will not fire.
My question is: How can I execute a function when a disabled checkbox is clicked?

I was looking through StackOverflow yesterday and found this solution in a question somewhere, but I now I can't find it again. When I find it, I'll link back to it.
The Fix
In order to capture clicks on a disabled checkbox, you can overlay a div above the disabled checkbox, and the div will receive all the onClick events (demo here):
<style type="text/css">
.checkboxWrapper {
position: relative;
}
.checkboxOverlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
</style>
<script type="text/javascript">
function notify() {
alert("Hello");
}
</script>
<span class="checkboxWrapper">
<input type="checkbox" disabled/>
<div class="checkboxOverlay" onclick="notify();"></div>
</span>
This places the div over the checkbox.
Internet Explorer
There's a bug in Internet Explorer, where the div is forced beneath the checkbox, and so the div can't receive click events because the checkbox blocks it. I've read that this happens because Internet Explorer treats the checkbox as an ActiveX control, and ActiveX controls get placed above all other elements.
In order to get around this Internet Explorer bug, we need to place a background on the div. I'm not sure why, but that causes the div to pop to the top. We can just create a transparent image and use it as the background for the div. I created a 1x1 transparent gif and set it as the background on the checkboxOverlay div:
.checkboxOverlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: url(img/transparent.gif) repeat;
}
Now it will work in Internet Explorer.

$('.mycontainer').delegate(':checkbox:disabled', 'click', function(e) {
//do stuff
});

Try wrapping each input in a div and attaching the onclick to the div. On a side note, you'd probably want the tooltip to show on hover instead of on click. Take a look at YUI's event utility if you're not using a library.

If you don't want to wrap the checkbox in a div, then consider not diabling checkbox and modifying the built-in click event on the checkbox:
document.getElementById("checkboxId").addEventListener("click", function (event) {
event.preventDefault();
//The code you want to be run when the checkbox is clicked
});

In Angular 4+
.html ->
<label class="round-check" (click)="validate()">
<input type="checkbox" [(ngModel)]="item.isChecked" [disabled]="true">
<span> {{item.text}}</span>
</label>
.ts ->
validate(){
this._toastr.warning('your warning msg')
}

Using jQuery it is simple: $('#thisOneDoesnt').trigger('click'); Live demo here. Using clean javascript doesn't work: document.getElementById('thisOneDoesnt').click(); - i don't know why, but i'm working on it.
EDIT
In JavaScript You can enable, click and disable checkbox. Live demo here.
document.getElementById('thisOneDoesnt').disabled = false;
document.getElementById('thisOneDoesnt').click();
document.getElementById('thisOneDoesnt').disabled = true;

Related

jQuery click event on disabled checkbox not firing

I have a list of checkboxes and i'm trying to limit to 2 maximum checkboxes by disabling all unchecked checkboxes after 2 have been selected.
This works fine, but i'm trying to display a message to the user if they click on a disabled checkbox to let them know why can't select more than 2. I'm trying to fire a click() event on a disabled checkbox but it doesn't actually fire. Any ideas?
var totalChecked = 0;
var checkedLimit = 1;
jQuery(".post-to-facebook").change(function() {
if (jQuery(this).attr("checked") == "checked") {
if (totalChecked < checkedLimit) {
totalChecked += 1;
if (totalChecked == checkedLimit) {
jQuery(".post-to-facebook[checked!='checked']").attr("disabled", true);
}
} else {
jQuery(this).attr("checked", false);
alert("You can only post twice to Facebook at one time. This is to avoid spam complaints, we don't want to spam on your page!");
}
} else {
totalChecked -= 1;
if (totalChecked < checkedLimit) {
jQuery(".post-to-facebook[checked!='checked']").attr("disabled", false);
}
}
console.log(totalChecked);
});
// THIS DOES NOT FIRE
jQuery(".post-to-facebook:disabled").click(function() {
alert("You can only post twice to Facebook at one time. This is to avoid spam complaints, we don't want to spam on your page!");
});
(from my answer at How to disable/enable a checkbox on right-click in chrome and firefox )
You could stack a transparent element on top of it (so the user can't see it), same size/shape, and listen for that click event. When it's enabled, hide that stacked element.
Here's something to get you started: http://jsfiddle.net/8dYXd/4/
It uses this structure:
<span>
<input id='a' type='checkbox' disabled="disabled" />
<span class="disabled-detector"></span>
</span>
And this CSS:
span {
position: relative;
}
span.disabled-detector {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
opacity: 0;
}
input+span.disabled-detector {
display: none;
}
input[disabled]+span.disabled-detector {
display: inline;
}
Notice how you can still "click" on disabled elements.
Technically, you could just use the parent <span> - give it a special class, and listen for click events on that. The events will bubble up from its descendants, so that should be fine.
Disabled elements don't receive events since they're entirely disabled.
You would need to pretend things were disabled with CSS and JavaScript itself. In this way you can apply styles, including pointers (or lack of), to mimic a disabled state and yet still receive events. You could also overlay the elements with another element and listen to events on that thing.
It's not firing a click event because it's disabled. You could address this by temporarily overlaying it with another element and handling the onclick of the overlay. Otherwise, you'll have to just gray it out with styling so that it only looks disabled.
Making the checkbox readonly can help, because the events will be fired. Though be aware of the differences in behaviour.
<input type="checkbox" name="yourname" value="Bob" readonly="readonly" />

Hide div on mouse click

I've created dialog windows; and I want them to be closed whenever the uses clicks anywhere else than the dialog window buttons (hyperlinks).
I was creating one large "overlay" div (0 opacity) at the back of dialog window to catch the clicks, but that becomes quite problematic when the user wants to clck anything at the back (like another hyperlink) as well as closing the dialog at the same time. Since there is overlay, it becomes activated (to close the dialog) and the clicked hyperlink is not catched.
Shortly, I need a solution for this situation where I'll close the dialog windows whenever user does anything except clicking the dialog window buttons.
I hope it's clear; thank you.
This is being caused by event bubbling. It's a shame that 2 people downvoted #Lilith2k3 answer because he wasn't wrong and #Xotic750 had way too complex a solution. You do need an event handler on your body, but you need simply to filter out clicks from the your dialog.
You need two onclick() handlers. One in your body to close the dialog, and the other in your dialog to cancel event bubbling. See below
function dlgClickHandler(e) {
// do dialog stuff, then...
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); // cancel event bubbling so body click handler not activated
}
function bodyClickHandler(e) {
// close dlg
}
This is also the reason you can't do this simply by comparing the ID of the dialog, because the click may have come from one of the children (eg. your OK, cancel buttons).
Working DEMO
Without jQuery DEMO
I've wrapped the functions in a module pattern to make it a neater component, and although I've used jQuery in the first example (which I suspect you are not) the technique pre-dates jQuery.
One of the reasons I suspect you're not using jQuery, is because if you were you'd probably already have stumbled across one of the many jQuery popup plugins for handing dialogs like this. If you've not tried jQuery take a look, it might help you out in many other ways too.
This is a very basic demonstration. We have a yellow div on the screen that represents your dialog. If you click anywhere in the div then it remains visible, you could fill this div with more HTML and event handlers to do as you wish. Click anywhere outside of the div and the div will become hidden. Note: I am not cleaning up any event handlers, which you will want to do.
Please see the answer by cirrus, where he actually gives an explanation about event propagation and why you will need it in your solution, which I haven't done here. He also gives you a solution using vanilla javascript and jquery, which I don't. He also demonstrates the javascript module pattern where I have not. I wouldn't have been able to bring you this answer without his constructive critisism and tuition, which prompted me to come back here and improve on my original poor, time constrained answer. Good luck.
CSS
.box {
width:300px;
height:100px;
position: absolute;
top: 30%;
left: 30%;
background-color:yellow;
border:2px solid;
}
#message {
position: absolute;
right: 50%;
bottom: 50%;
}
#button1 {
position: absolute;
right: 0;
bottom: 0;
}
#button2 {
position: absolute;
right: 4em;
bottom: 0;
}
HTML
<div id="box" class="box">
<div id="message"></div>
<button id="button1">
<img src="http://img856.imageshack.us/img856/3817/ticklf.png" alt />Ok</button>
<button id="button2">
<img src="http://img822.imageshack.us/img822/1917/crossn.png" alt />Cancel</button>
</div>
JavaScript
function dontBubble(evt) {
evt.stopPropagation();
}
function hideBox(evt) {
box.hidden = true;
}
function messgage() {
document.getElementById("message").textContent = "I'm ignoring you";
}
document.getElementById("box").addEventListener("click", dontBubble, false);
document.getElementById("button1").addEventListener("click", messgage, false);
document.getElementById("button2").addEventListener("click", hideBox, false)
document.addEventListener("click", hideBox, false)
;
On jsfiddle
At best, you would bind a click event to $("body"), which checks, where the user clicked and in case the user clicked not within the dialog, you could unbind the event and close the dialog.

Button element not firing click event when clicking on button text and releasing off it (but still inside the button)?

On WebKit browsers (I tested on Chrome and Safari on Mac), button element behaves weird:
Wen in this fiddle http://jsfiddle.net/5ReUn/3/ you do the following:
Press left mouse button while the cursor is over HTML button text
Move the cursor (while pressed) to an area of the button without text
Release the mouse button
Then the click event on the button element is not fired!
HTML is very simple:
<button id="button">Click</button>
And the CSS is not sophisticated at all:
button {
display: block;
padding: 20px;
}
JS for click catching:
button = document.getElementById('button');
button.addEventListener('click', function() {
console.log('click');
});
Many visitors to my site complain that buttons are not clickable. They don't realize they are moving the cursor while clicking.
Has anybody found a workaround for this?
It turns out to be a bug in WebKit.
An quick non-JavaScript solution is to wrap the text in a SPAN element and make it click-through:
<button>
<span>Click Me</span>
</button>
Example CSS:
span {
display: block;
padding: 20px;
pointer-events: none; // < --- Solution!
}
Since the bug appears only in WebKit, browsers that don't support pointer-events can be ignored.
If you don't find another solution, you can use the mousedown event instead of the click event.
This is not the best solution since it behaves different than normal. Normally the user is expecting the action to happen when the finger is released from the mouse button. Not when the finger is holding the mouse button down.
Here you are trying to drag instead of clicking it. So, you may want to try mousedown event instead.
//This is same as click event
var down = false;
var button = document.getElementById('button');
var info = document.getElementById('info')
button.addEventListener('mousedown', function() {
down = true;
});
button.addEventListener('mouseup', function() {
if(down){
info.innerHTML += "click ";
down = false;
}
});
jsfiddle
You could add a div around the button (with like a margin of what, 20px?) with the same js/jquery bound to it. That way, if they would missclick(lol) the script would still fire. However, I noticed that indeed if you drag your mouse off the button while it's pressed, the button will not do anything (doesn't just happen on your page, i.e. try it with Facebook-login buttons or even the buttons on this website).

Mobile Safari: Javascript focus() method on inputfield only works with click?

I have a simple input field like this.
<div class="search">
<input type="text" value="y u no work"/>
</div>​
And I'm trying to focus() it inside a function.
So inside of a random function (doesn't matter what function it is) I have this line …
$('.search').find('input').focus();
This works just fine on every Desktop whatsoever.
However it doesn't work on my iPhone. The field is not getting focused and the keyboard is not shown on my iPhone.
For testing purposes and to show you guys the problem I did a quick sample:
$('#some-test-element').click(function() {
$('.search').find('input').focus(); // works well on my iPhone - Keyboard slides in
});
setTimeout(function() {
//alert('test'); //works
$('.search').find('input').focus(); // doesn't work on my iPhone - works on Desktop
}, 5000);​
Any idea why the focus() wouldn't work with the timeout function on my iPhone.
To see the live example, test this fiddle on your iPhone. http://jsfiddle.net/Hc4sT/
Update:
I created the exact same case as I'm currently facing in my current project.
I have a select-box that should — when "changed" — set the focus to the input field and slide-in the kexboard on the iphone or other mobile devices. I found out that the focus() is set correctly but the keyboard doesn't show up. I need the keyboard to show up.
Actually, guys, there is a way. I struggled mightily to figure this out for [LINK REMOVED] (try it on an iPhone or iPad).
Basically, Safari on touchscreen devices is stingy when it comes to focus()ing textboxes. Even some desktop browsers do better if you do click().focus(). But the designers of Safari on touchscreen devices realized it's annoying to users when the keyboard keeps coming up, so they made the focus appear only on the following conditions:
1) The user clicked somewhere and focus() was called while executing the click event. If you are doing an AJAX call, then you must do it synchronously, such as with the deprecated (but still available) $.ajax({async:false}) option in jQuery.
2) Furthermore -- and this one kept me busy for a while -- focus() still doesn't seem to work if some other textbox is focused at the time. I had a "Go" button which did the AJAX, so I tried blurring the textbox on the touchstart event of the Go button, but that just made the keyboard disappear and moved the viewport before I had a chance to complete the click on the Go button. Finally I tried blurring the textbox on the touchend event of the Go button, and this worked like a charm!
When you put #1 and #2 together, you get a magical result that will set your login forms apart from all the crappy web login forms, by placing the focus in your password fields, and make them feel more native. Enjoy! :)
A native javascript implementation of WunderBart's answer.
function onClick() {
// create invisible dummy input to receive the focus first
const fakeInput = document.createElement('input')
fakeInput.setAttribute('type', 'text')
fakeInput.style.position = 'absolute'
fakeInput.style.opacity = 0
fakeInput.style.height = 0
fakeInput.style.fontSize = '16px' // disable auto zoom
// you may need to append to another element depending on the browser's auto
// zoom/scroll behavior
document.body.prepend(fakeInput)
// focus so that subsequent async focus will work
fakeInput.focus()
setTimeout(() => {
// now we can focus on the target input
targetInput.focus()
// cleanup
fakeInput.remove()
}, 1000)
}
Other References: Disable Auto Zoom in Input "Text" tag - Safari on iPhone
I faced the same issue recently. I found a solution that apparently works for all devices. You can't do async focus programmatically but you can switch focus to your target input when some other input is already focused. So what you need to do is create, hide, append to DOM & focus a fake input on trigger event and, when the async action completes, just call focus again on the target input. Here's an example snippet - run it on your mobile.
edit:
Here's a fiddle with the same code. Apparently you can't run attached snippets on mobiles (or I'm doing something wrong).
var $triggerCheckbox = $("#trigger-checkbox");
var $targetInput = $("#target-input");
// Create fake & invisible input
var $fakeInput = $("<input type='text' />")
.css({
position: "absolute",
width: $targetInput.outerWidth(), // zoom properly (iOS)
height: 0, // hide cursor (font-size: 0 will zoom to quarks level) (iOS)
opacity: 0, // make input transparent :]
});
var delay = 2000; // That's crazy long, but good as an example
$triggerCheckbox.on("change", function(event) {
// Disable input when unchecking trigger checkbox (presentational purpose)
if (!event.target.checked) {
return $targetInput
.attr("disabled", true)
.attr("placeholder", "I'm disabled");
}
// Prepend to target input container and focus fake input
$fakeInput.prependTo("#container").focus();
// Update placeholder (presentational purpose)
$targetInput.attr("placeholder", "Wait for it...");
// setTimeout, fetch or any async action will work
setTimeout(function() {
// Shift focus to target input
$targetInput
.attr("disabled", false)
.attr("placeholder", "I'm alive!")
.focus();
// Remove fake input - no need to keep it in DOM
$fakeInput.remove();
}, delay);
});
label {
display: block;
margin-top: 20px;
}
input {
box-sizing: border-box;
font-size: inherit;
}
#container {
position: relative;
}
#target-input {
width: 250px;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container">
<input type="text" id="target-input" placeholder="I'm disabled" />
<label>
<input type="checkbox" id="trigger-checkbox" />
focus with setTimetout
</label>
</div>
This solution works well, I tested on my phone:
document.body.ontouchend = function() { document.querySelector('[name="name"]').focus(); };
enjoy
I have a search form with an icon that clears the text when clicked. However, the problem (on mobile & tablets) was that the keyboard would collapse/hide, as the click event removed focus was removed from the input.
Goal: after clearing the search form (clicking/tapping on x-icon) keep the keyboard visible!
To accomplish this, apply stopPropagation() on the event like so:
function clear ($event) {
$event.preventDefault();
$event.stopPropagation();
self.query = '';
$timeout(function () {
document.getElementById('sidebar-search').focus();
}, 1);
}
And the HTML form:
<form ng-controller="SearchController as search"
ng-submit="search.submit($event)">
<input type="search" id="sidebar-search"
ng-model="search.query">
<span class="glyphicon glyphicon-remove-circle"
ng-click="search.clear($event)">
</span>
</form>
I managed to make it work with the following code:
event.preventDefault();
timeout(function () {
$inputToFocus.focus();
}, 500);
I'm using AngularJS so I have created a directive which solved my problem:
Directive:
angular.module('directivesModule').directive('focusOnClear', [
'$timeout',
function (timeout) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var id = attrs.focusOnClear;
var $inputSearchElement = $(element).parent().find('#' + id);
element.on('click', function (event) {
event.preventDefault();
timeout(function () {
$inputSearchElement.focus();
}, 500);
});
}
};
}
]);
How to use the directive:
<div>
<input type="search" id="search">
<i class="icon-clear" ng-click="clearSearchTerm()" focus-on-clear="search"></i>
</div>
It looks like you are using jQuery, so I don't know if the directive is any help.
UPDATE
I also tried this, but to no avail:
$(document).ready(function() {
$('body :not(.wr-dropdown)').bind("click", function(e) {
$('.test').focus();
})
$('.wr-dropdown').on('change', function(e) {
if ($(".wr-dropdow option[value='/search']")) {
setTimeout(function(e) {
$('body :not(.wr-dropdown)').trigger("click");
},3000)
}
});
});
I am confused as to why you say this isn't working because your JSFiddle is working just fine, but here is my suggestion anyway...
Try this line of code in your SetTimeOut function on your click event:
document.myInput.focus();
myInput correlates to the name attribute of the input tag.
<input name="myInput">
And use this code to blur the field:
document.activeElement.blur();
Try this:
input.focus();
input.scrollIntoView()
Please try using on-tap instead of ng-click event. I had this issue. I resolved it by making my clear-search-box button inside search form label and replaced ng-click of clear-button by on-tap. It works fine now.

How do a get buttons not to take the focus?

I want my (ExtJS) toolbar buttons not to grab the focus on the web page when they are clicked, but to do their "thing" while leaving the focus unchanged by the click. How do I do that?
Cancelling the default behavior of onmousedown prevents an element from getting the focus:
// Prevent capturing focus by the button.
$('button').on('mousedown',
/** #param {!jQuery.Event} event */
function(event) {
event.preventDefault();
}
);
document.activeElement stores the currently focussed element.
So on your toolbar, you can add a "mousedown" handler to this function :
function preventFocus() {
var ae = document.activeElement;
setTimeout(function() { ae.focus() }, 1);
}
Try this example :
<html>
<head>
<script>
function preventFocus() {
var ae = document.activeElement;
setTimeout(function() { ae.focus() }, 1);
}
</script>
</head>
<body>
<input type="text"/>
<input type="button" onmousedown="preventFocus()" onclick="alert('clicked')" value="Toolbar" />
</body>
</html>
This usually does the trick for me:
<button
tabindex="-1"
onclick="javascript:console.log('do your thing')"
>My Button</button>
From https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex:
A negative value (usually tabindex="-1") means that the element should be focusable, but should not be reachable via sequential keyboard navigation. It's mostly useful to create accessible widgets with JavaScript.
I don't think there's an easy way to do what you want to do because it's the browser's default behaviour.
You could of course blur() the button as soon as it is clicked, but that would simply unselect everything. To have the previously active object regain focus, you'd have to create a "memory" of sorts by adding a blur handler for every element to keep track of which element had/lost focus last (store the id of the element in a global and update it when an element loses focus).
The top-voted answer is technically correct, but depends on jQuery...
Here's a simpler example:
<span onclick="document.execCommand('bold', false);" onmousedown="event.preventDefault();"></span>
My solution is to replace <button /> with <div /> and style it as a button.
Looks like Div doesn't take a focus on it when you click it.
Because the toolbar buttons are just styled ordinary HTML button elements then this is an actual browser behavior, and you should think twice before changing it. But nevertheless...
You should be able to prevent the botton from receiving focus by just returning false from its onclick handler.
Maybe you should try to use stateful and state change properties for form fields or whatever to get focus back?
I would attach one blur event listener to all fields. This listener should save the field, that lost the focus, in a global variable.
Then all the toolbar button should get one focus event listener. This listener should focus the field, that was saved as described above.
This code should work, although it didn't test it
<script>
function focusor(){
document.getElementById('focus').focus;
}
document.onkeydown = focusor;
document.onclick = focusor;
</script>
<div style="width: 0px; height: 0px; overflow: hiddden;">
<button id="focus"></button>
</div>
What I have found, is you will have to make a dummy element, I found buttons to work best in this situation. put the button in a div and make the div 0px.
[do not make the div display none, some browsers will just ignore it]
Basically any click or button presses, it will focus on this dummy button.
I had a project very similar and whenever they pressed the down key it selected the first button on the page, this just focuses on the button over and over again.
Sort of jacked up, but it works.
All these answers are wack. Here's a very excellent trick that only uses CSS
<button type="submit" disabled>
<span>Submit</span> <!-- the <span> is the secret -->
</button>
Now in your css:
button[disabled] > * {
pointer-events: none;
}
The trick is the inner span has to be used, otherwise the button will still steal focus away from inputs.

Categories

Resources