How to trigger a click event on disabled elements - javascript

I have a disabled button, which is enabled after checking "I accept terms and conditions" checkbox.
The problem is that I wanted to trigger an alert, if a user clicks the disabled button. How can I do this? If an element is disabled, it looks as "onclick" events are not fired.
The sample of the code:
<input id="subm_tc" class="btn btn-primary" type="submit" disabled="" value="Log in" name="Submit">
$("#subm_tc").click(function () {
if($("#modlgn-tc").is(':checked')){
alert('checked');
} else {
alert('unchecked');
}
});
If I wrap the element in div and listen to clicks on that div, it works, but you need to click outside the button.
How can I fix this?
Thanks
UPDATE. I've managed to resolve this by adding a fake div over the submit button and listening to events on that div (I also change z-index to -200 to enable clicks on the button itself):
<div style="position:relative">
<div id="subm_tc" style="position: absolute; left: 0px; right: 0px; bottom: 0px; top: 0px; z-index: 99999;"></div>
<input id="subm_tc" class="btn btn-primary" type="submit" disabled="" value="Log in" name="Submit">
</div>
Now it works as intended

My solution was to put the button in a div, which is clickable. when the button is disabled, the div has the width and height of the button, so clicking the button triggers the div. when the button is enabled, the div is shrunk to 0 width 0 height, so the click event registers with the button instead of the div. This code includes some demoing code as well for a toggle button which toggles the enabled/disabled state of the button in question
fiddle: http://jsfiddle.net/6as8b/2/
HTML
Click 'Toggle" to make 'Button' enabled or disabled. click it, and see that that one event fires if it is enabled, and another if disabled.
<input type=button value='toggle' id='toggle'><BR>
<div style='position:relative'>
<div id='clickable'></div>
<input id=theButton type=button disabled value='Button'>
</div>
<div id=clicks></div>
CSS
#clickable{
position:absolute;
width:55px;
height:25px;
}
JS
$(document).ready(function () {
$('#clickable').on('click',function () {
if ($('#theButton:disabled').length>0)
{
$('#clicks').append('|Disabled Button Clicked|<br>');
}
else
{
//do nothing and let the button handler do it
$('#theButton').click();
}
});
$('#theButton').on('click',function() {
$('#clicks').append('|ENABLED button clicked|<br>');
});
$('#toggle').on('click',function() {
if ($('#theButton:disabled').length>0)
{
$('#theButton').removeAttr('disabled');
$('#clickable').css({'width':'0px','height':'0px'});
}
else
{
$('#theButton').attr('disabled','disabled');
$('#clickable').css({'width':'55px','height':'25px'});
}
});
});

Disabled elements doesn't trigger any mouse events at all, so that's probably a lost cause.
However, when clicking a parent element, the event.target seems to be given correctly, which means this should work :
$(document).on('click', function (e) {
if (e.target.id == 'subm_tc') {
if($("#modlgn-tc").is(':checked')){
alert('checked');
} else {
alert('unchecked');
}
}
});
FIDDLE

You can write a function that adds listeners to the mousedown and mouseup events, and if the targets match your Node (i.e. the mousedown and following mouseup were on your element), then it invokes another function
function listenFullClick(elm, fn) {
var last;
document.addEventListener('mousedown', function (e) {
last = e.target === elm;
});
document.addEventListener('mouseup', function (e) {
if (e.target === elm && last) fn();
});
};
listenFullClick(
document.getElementById('foo'), // node to look for
function () {alert('bar');} // function to invoke
);
DEMO

Old topic, but here are my two cents as I had the same challenge lately:
Don't try to position a clickable element above it but wrap it with one so you won’t directly be able to click it. Assuming a button with display: inline-block set:
<span class="on-disabled">
<input id="subm_tc" class="btn btn-primary" type="submit" disabled value="Log in" name="Submit">
</span>
Define you click event for the case of the button being disabled:
$('.on-disabled').click(function (ev) {
// Don’t react to click events bubbling up
if (ev.target !== ev.currentTarget) return;
// Do your thing
alert('Sorry, this button is disabled');
});
And simply style the button like:
#subm_tc {
display: inline-block;
}
#subm_tc[disabled] {
position: relative;
z-index: -1;
}
This allows you to easily react to a click even in case of a disabled button.
See FIDDLE.

If you use Twitter Bootstrap, they give you a class disabled that provides the styling but doesn't remove the click event. Given that, what I did was this (keep in mind also, I wanted to be sure that when the button was no longer disabled, the original click event did fire, and I didn't want to deal with unbinding, rebinding it).
function disableButton(btn, message) {
btn.addClass("disabled")
if (!(message == null || message == "")) {
btn.data("message", message)
}
}
function enableButton(btn) {
btn.removeClass("disabled")
}
$("#btn").click(function() {
if (!($(this).hasClass("disabled"))) {
// original, desired action
} else {
message = $(this).data("message")
if (!(message == null || message == "")) {
alert(message)
}
}
})

2022 Update: I know this is an old question, but here's an update after evaluating various solutions, including CSS position:absolute and pointer-events:none
The disadvantage of simulating the disabled look ("Pretend Disable") was that, back then, various browsers presented disabled elements differently. That's not as true today because Chrome, Edge, Firefox, and other modern browsers, implement disabled button inputs (and likely other inputs) with the equivalent of opacity .5 .
The solution below is inspired by https://css-tricks.com/making-disabled-buttons-more-inclusive which uses the aria-disabled attribute in place of the older disabled attribute. That article strongly advised against using CSS techniques such as position:absolute and pointer-events:none, because when disabled, the input (or underlying/overlying element) cannot receive focus preventing the possibility of an automatic tooltip when tabbed to and preventing a screen reader from announcing the element is disabled.
Accessible Rich Internet Applications (ARIA) is a set of attributes that define ways to make web content and web applications (especially those developed with JavaScript) more accessible to people with disabilities.
HTML:
<input type='button' id='toggle' value='Toggle'>
<input type='button' id='theButton' value='Button'>
<div id='clicksReport'></div>
Plain JavaScript:
document.querySelector('#theButton').onclick = function () {
if (document.querySelector('#theButton').ariaDisabled)
{
// Your disabled button code (if any)
document.querySelector('#clicksReport').insertAdjacentHTML("beforeend",'|Disabled Button Clicked|<br>');
}
else
{
// Your emabled button code
document.querySelector('#clicksReport').insertAdjacentHTML("beforeend",'|ENABLED button clicked|<br>');
}
}
document.querySelector('#toggle').onclick = function() {
if (document.querySelector('#theButton').ariaDisabled)
{
// If not a button input, also remove the readOnly attribute
var el = document.querySelector('#theButton');
el.ariaDisabled = null;
el.style.opacity = null;
}
else
{
// If not a button input, also set the readOnly attribute
var el = document.querySelector('#theButton');
el.ariaDisabled = true;
el.style.opacity = '.5';
}
}
JS Fiddle: https://jsfiddle.net/SKisby/3Lna8q7h/7/
The same in d3 (as that's what I'm currenlty using and it's similar to jQuery):
d3.select('#theButton').on('click',function () {
if (d3.select('#theButton').attr('aria-disabled'))
{
// Your disabled button code (if any)
d3.select('#clicksReport').node().insertAdjacentHTML("beforeend",'|Disabled Button Clicked|<br>');
}
else
{
// Your emabled button code
d3.select('#clicksReport').node().insertAdjacentHTML("beforeend",'|ENABLED button clicked|<br>');
}
});
d3.select('#toggle').on('click',function() {
if (d3.select('#theButton').attr('aria-disabled'))
{
// If not a button input, also remove the readOnly attribute
d3.select('#theButton').attr('aria-disabled',null)
.style('opacity',null);
}
else
{
// If not a button input, also set the readOnly attribute
d3.select('#theButton').attr('aria-disabled',true)
.style('opacity','.5');
}
});
d3 Fiddle: https://jsfiddle.net/SKisby/qkvf3opL/2/
The above are simple, both have the same disabled look in Chrome, Firefox, and other modern browsers, and have the benefits of being able to receive focus (where an automatic tooltip could then be implemented and ARIA screen readers can convey the element is effectively disabled).
If the input is not a button, also set and remove the readOnly attribute.

Related

onclick fires only once when trying to change checked attribute

I want to change of status of an input checkbox when click on another element.
But click triggers only once that code block.
#menu-state:checked {
background: red;
}
#menu-state {
background: blue;
}
<input type="checkbox" id="menu-state" class="menu-state">
<a href="#menu-state" role="button" class="menu-anchor menu-anchor-open"
id="menu-anchor-open"></a>
$("#menu-anchor-open").on("click", function (e) {
e.preventDefault()
if ($('#menu-state').prop('checked')) {
$('#menu-state').attr('checked', false);
} else {
$('#menu-state').attr('checked', true);
}
});
In first click, it adds checked="checked" on the input, but on another clicks, it doesnt work.
I have also tried those solutions too;
Changing a checkbox's state programmatically in dashcode
Checkbox click function is not working
Setting "checked" for a checkbox with jQuery
jquery check all input:checkbox on button click
What am i missing?
For example below works on every click. But previous one doesnt work.
$("#menu-anchor-open").on("click", function (evt) {
evt.preventDefault()
if ($('#menu-state').hasClass('open')) {
$('#menu-state').removeClass('open');
} else {
$('#menu-state').addClass('open');
}
});

Can you stop the jQuery focusout from firing when losing focus?

I've got an input box that I want to have save its value when it loses focus.
Pretty straightforward stuff and I'm able to get that done via jQuery's focusout event.
The problem however, is that I want to NOT fire the focusout event when the user clicks on an "X" icon next to the input box (example shown below)
So when the user tabs out of this input box, or clicks outside of the box or they click the green checkbox it should fire the focusout event... but if they click the red "X", it should NOT fire the focusout.
Is this possible to do with JavaScript / jQuery?
EDIT:
Some of you have recommended using event.relatedTarget, but it seems like that's returning null. I'll include my code in question for clarity:
// This is the cancel button with the red X
$("body").on("click", "span[id*='Cancel']", function(e)
{
showLabel($(this));
});
// this is the code to trigger the blur / focusout event
// trouble is that the "e.relatedTarget" is null
$("body").on("focusout", "input, textarea", function (e) {
if($(e.relatedTarget).is("span[id*='Cancel']")){
return false;
}
$(this).siblings("span[id*='OK']").trigger("click");
return false;
});
Here's a screen grab of me debugging this in JS (you'll see that the $(e.relatedTarget) selector returns nothing):
You can cancel de event returning the focus to previous element.
$('#inputText').focusout(function(event) {
setTimeout(function(){
if (document.activeElement.id == "btnCancel") {
$(event.target).focus();
return false;
}
},1);
});
This jsFiddle shows how to do it: https://jsfiddle.net/mpervh3t/
Hope it helps
You must use relatedTarget like this :
$(document).ready(function(){
$(".btn").on("focusout",function(e){
if($(e.relatedTarget).hasClass("red")) {
alert("You clicked on X button");
}
else {
alert("Fire Focus out")
}
})
})
Final code :
<!DOCTYPE html>
<html>
<head>
<style>
.gr {
color: green;
}
.red {
color: red;
}
</style>
</head>
<body>
<input type="text" class="btn"><button class="gr">Ok</button><button class="red">X</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
$(".btn").on("focusout",function(e){
if($(e.relatedTarget).hasClass("red")) {
alert("You clicked on X button");
}
else {
alert("Fire Focus out")
}
})
})
</script>
</body>
</html>
As per my comment:
"I have had to do a similar type of thing with a blur event. Basically what I had to do was call a setTimeout on the blur to execute my function to save the data, and then on the click event of the X, cancel the timeout. That way, unless the X is clicked, the save function will fire. The delay can be pretty negligable, too."
I found the relevant code
var sliderTimeout = null;
$(".slider-trigger").on("blur", function () {
sliderTimeout = setTimeout(function () {
$(".slider").hide();
}, 100);
});
$(".ui-slider-handle").on("focus", function () {
clearTimeout(sliderTimeout);
});
Here is the full demo of the code in action. It does much more than demonstrate this, but if you examine the behavior of focusing/blur on the "margin" input, you will see that if you blur the margin input, the slider hides, but if you click on the slider, it cancels the hide and stays shown. It's the exact same concept, just a slightly different application.
Here, I did the thing.
https://jsfiddle.net/kowmLf2a/1/
In the blur event I target the related target. See if that related target is the item that I don't want to blur with. If it is then return false.
Code for reference:
$('#input').blur(function(event){
if($(event.relatedTarget).is('#bt2')){
return false;
}
alert($(this).val());
});

Why submit button is not enabled immediately on change to textfield?

With this code The button will become enabled only after:
I type something in textfield
I change the focus out of the textfield.
How can I get the button to enable as soon as something is typed in?
function validateAmount(){
if ($('#parlay-amount-textfield').val().length > 0) {
$("#parlay-submit-button").prop("disabled", false);
}
else {
$("#parlay-submit-button").prop("disabled", true);
}
}
$(document).ready(function(){
validateAmount();
$('#parlay-amount-textfield').change(validateAmount);
});
The change event doesn't fire until focus leaves the input field.
You can use the input event instead on modern browsers, which fires immediately. Or a combination of events to support slightly older browsers: input change paste click which you can respond to immediately and then keydown which you need to respond to after a very brief delay. But I think input's support is very good these days, with the notable exception of IE8 which doesn't support it.
Example with just input:
function validateAmount() {
if ($('#parlay-amount-textfield').val().length > 0) {
$("#parlay-submit-button").prop("disabled", false);
} else {
$("#parlay-submit-button").prop("disabled", true);
}
}
$(document).ready(function() {
validateAmount();
$('#parlay-amount-textfield').on("input", validateAmount);
});
<input type="text" id="parlay-amount-textfield">
<input type="button" id="parlay-submit-button" value="Send">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Example with input change paste click handled immediately and keydown after a very brief delay:
function validateAmount() {
if ($('#parlay-amount-textfield').val().length > 0) {
$("#parlay-submit-button").prop("disabled", false);
} else {
$("#parlay-submit-button").prop("disabled", true);
}
}
$(document).ready(function() {
validateAmount();
$('#parlay-amount-textfield')
.on("input change paste click", validateAmount)
.on("keydown", function() {
setTimeout(validateAmount, 0);
});
});
<input type="text" id="parlay-amount-textfield">
<input type="button" id="parlay-submit-button" value="Send">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Side note: FWIW, validateAmount can be a bit shorter:
function validateAmount() {
$("#parlay-submit-button").prop("disabled", $('#parlay-amount-textfield').val().length == 0);
}
And if just spaces isn't a valid value, you might consider throwing a $.trim() around $('#parlay-amount-textfield').val() (or on modern browsers, using $('#parlay-amount-textfield').val().trim()).
Since we are using the change event the input fields focus tends to say that user has not yet ended up his field with data.so only after the focus is moved the button gets enabled u can use the above Link for further clarifications
[1]"https://jsfiddle.net/MuthuramanNagarajan/gs2sff6j/"

javascript event handlers list

I am trying to prioritize click event in case two events click and change are fired.
I have a global function similar to "ValidateOnChange" and "ValidateOnClick" to validate input of text box on change and on click event.
Enter some text, it shows up error message. Then try to input correct value and click the Submit button, the error vanishes and this makes user to click the button twice. Here I am trying to fix this double click.
Here is mock up code:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
</head>
<body>
<div>Enter any string:</div>
<div><input type="text" id="txtInput" ></input></div>
<div id="divError" style="color: red; display: none;">Please enter 0</div>
<input type="button" value="Submit" id="btnSubmit" ></input>
<script type="text/javascript">
var mouseevent_var = null;
function ValidateOnChange(e) {
var input = $('#txtInput').val();
if (input == '0') {
$('#divError').hide();
} else {
$('#divError').show();
}
}
function ValidateOnClick(e){
alert("Hurray!!! You got it right!");
}
$('#txtInput').mousedown(function (e) {
mouseevent_var = e;
});
jQuery(document).ready(function(){
$('#btnSubmit').click(function(e){
ValidateOnClick(e);
});
$('#txtInput').change(function(e){
ValidateOnChange(e);
});
//User don't want error when they are typing in.
//$('#txtInput').keyup(function() {
//$('#txtInput').trigger("change");
//});
});
</script>
</body>
</html>
The keyup event seemed to be solution but users don't want the error to popup when they are typing in.
Is there any way to list all the triggered events so that I could filter "mousedown" and "mouseup" events for submit button? Or is there any alternative way to prioritize click event ?
There can be many alternatives depending on the situations. I have made few minor changes to avoid the double click issue (comments amended). Basically we need to bind the mousedown event on the button object. There we will set a temporary flag variable to true. In the same time if input's change event gets fired then you can skip the checking if the temporary flag variable is true. Reason behind the double click for triggering the button's click event is better explained here: How to get jQuery click event after append in change event handler
Your updated js code below:
var mouseevent_var = false;
function ValidateOnChange(e) {
// Skip validation if the change event is fired due to user's click on submit button
if(mouseevent_var){ return false; }
var input = $('#txtInput').val();
if (input == 0) {
$('#divError').hide();
} else {
$('#divError').show();
}
}
function ValidateOnClick(e){
mouseevent_var = false; // Reset mouseevent_var to false
alert("Hurray!!! You got it right!");
}
$('#btnSubmit').mousedown(function (e) {
mouseevent_var = true;
});
jQuery(document).ready(function(){
$('#btnSubmit').click(function(e){
ValidateOnClick(e);
});
$('#txtInput').change(function(e){
ValidateOnChange(e);
});
//User don't want error when they are typing in.
//$('#txtInput').keyup(function() {
//$('#txtInput').trigger("change");
//});
});
The above code is just a fix as per your need. But there are other better alternatives too. Ideally you should not have two different validation functions for validating same fields on different events. You must think of managing it with a single function.

Day/Night mode - CSS + JQuery - Cookies?

I'm testing javascript code for day/light background switch and I don't know how to do something. I'm newbie to javascript, so I'm learning new stuff.
So what I want to do?
When I click for example on button "Day" (which change background to yellow), I want that style for yellow background stay in the code after page is refreshed. I heard something about Cookies/LocalStorage, but I don't know how to implement it for this code.
Feel free to change whole code if you know easier way to do this, but please explain why it's better or why it should be like that.
Thanks in advance for your help.
Here is the code:
HTML:
<body id="body">
<input type="button" onclick="day();" value="Day" />
<input type="button" onclick="night();" value="Night" />
<input type="button" onclick="reset();" value="Reset" />
</body>
CSS:
.darkSwitch {
background: #808080;
}
.lightSwitch {
background: #ffff99;
}
JavaScript:
function day() {
body.className = "lightSwitch";
};
function night() {
body.className = "darkSwitch";
};
function reset() {
body.className = "";
};
$(function() {
var button = $('input[type=button]');
button.on('click', function() {
button.not(this).removeAttr('disabled');
$(this).attr('disabled', '');
});
});
Last edit: now disabling selected button on page load, CODE NOT IN THIS POST, see the latest JSFiddle
Explanation
What I did:
The code is put in between<script> tags at the end of the <body> (personnal preference)
I added the parameter event to the onClick event of the button element.
I added event.preventDefault() at the start of the onclick event of the button element: ensuring the page is NOT refreshed on the click of a button.
Warning: ALL the buttons will behave the same in your page. If you have other buttons, I suggest you add another class for those three buttons and bind the event on the button.myClass element.
I added a condition on the button state change, so the reset button won't get disabled.
eval($(this).val().toLowerCase()+"();"); gets the value of the the clicked button and executes the function attached to it.
Solution
HTML
<body id="body">
<input type="button" class="changeBg" onclick="day();" value="Day" />
<input type="button" class="changeBg" onclick="night();" value="Night" />
<input type="button" class="changeBg" onclick="reset();" value="Reset" />
</body>
JavaScript
(JSFiddle) <-- Check this out Updated with classes & cookies
function day() {
body.className = "lightSwitch";
};
function night() {
body.className = "darkSwitch";
};
function reset() {
body.className = "";
};
$(function () {
/* RegEx to grab the "bgColor" cookie */
var bgColor = document.cookie.replace(/(?:(?:^|.*;\s*)bgColor\s*\=\s*([^;]*).*$)|^.*$/, "$1");
var button = $('input[type=button].changeBg');
button.on('click', function (event) {
event.preventDefault();
/* Executing the function associated with the button */
eval($(this).val().toLowerCase() + "();");
button.not($(this)).removeAttr('disabled');
if ($(this).val() != "Reset") {
$(this).attr('disabled', '');
/* Here we create the cookie and set its value, does not happen if it's Reset which is fired. */
document.cookie = "bgColor="+$(this).val();
}
});
/* If the cookie is not empty on page load, execute the function of the same name */
if(bgColor.length > 0)
{
eval(bgColor.toLowerCase()+'()');
/* Disable the button associated with the function name */
$('button[value="'+bgColor+'"]').attr("disabled","disabled");
}
});
I recommend you don't use cookies unless localStorage is not supported. They slow your site down.
if(localStorage){
localStorage.setItem("bgColor", "lightSwitch");
}else{
document.cookie = "bgColor=lightSwitch";
}

Categories

Resources