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" />
Related
I'm trying to toggle a button to either submit on click or reveal an input field depending on if the user clicks the document to hide/collapse the input field. The issue is that after the user dismisses the input field the submit button doesn't return to a toggle behavior; clicking the button to again open the input field results in form submission.
I need the button, when clicked, to trigger a search field to slide in. Once the input field is visible, the button will submit instead of toggle, unless, the user clicks on the document to hide the field. Currently, the initial click will open the input field, clicking on the document will collapse the field. The second click after either previous action will result in 'submit'.
I believe, based on my little understanding, that the preventDefault() function isn't occurring on the second click or, .off('click') needs to be toggled somehow?
HTML:
<form action="" id="sSearch" class="collapsed">
<input type="search" id="sSearch-Field" placeholder="Search">
<button type="submit">
Open
</button>
</form>
JS:
$('#sSearch button').click(function (event) {
event.preventDefault();
$('#sSearch').removeClass('collapsed');
$('#sSearch button').off('click');
});
$(document).click(function (event) {
$target = $(event.target);
if(!$target.closest('#sSearch').length && $('#sSearch').not('.collapsed')) {
$('#sSearch').addClass('collapsed');
}
});
I don't understand why the preventDefault() function doesn't work on the second click? Based on what I've seen in similar questions, the off() and unbind() functions should reset the click and default behavior. Is this true?
CodePen Example
There's already an answer here, but it doesn't explain why your code isn't working. From your question it is clear you are specifically trying to understand the problem, so let's solve it! :-)
You asked:
... the off() and unbind() functions should reset the click and default behavior. Is this true?
In this case, yes, that is pretty much what happens. More generally, off() will remove an event handler. In this case it removes the click handler that was added to the button.
So where's the problem? The first time that button handler runs, it removes itself from handling any future clicks. That means you'll never be able to display the search input again (which is what the handler normally does). If you click on the document to hide the search input, and then need to show it again, you can't. The handler which does that is no longer listening for clicks on your button!
Let's trace how that happens:
If the second click is on the document:
first handler is not attached to any events, will not fire;
second handler does fire;
!$target.closest('#sSearch').length will evaluate true;
$('#sSearch').not('.collapsed') will evaluate true
test passes, search field is hidden;
GOOD! This is what you want;
Now say you want to show the search input again, so you click the button:
first handler is not attached to any events, will not fire;
second handler does fire;
!$target.closest('#sSearch').length will evaluate false;
test fails, second handler does nothing;
neither handler did anything, default action was not prevented - the form will submit, just like a normal HTML form without any Javascript at all;
BAD! You this is not what you wanted.
Side note: $('#sSearch').not('.collapsed') works, but for readability and consistency it should probably be $('#sSearch').not('.collapsed').length, just like the first condition.
So, how to get the behaviour you want?
To stick with the approach you are using, you would need to re-attach the first event handler when the search field is hidden, so that the page goes back to the initial state, just like it is at page load.
To do that, I would extract the code into a function so that you can call it from 2 places, to avoid having to duplicate it:
// New function we can call whenever we need it
function showSearch (event) {
event.preventDefault();
$('#sSearch').removeClass('collapsed');
$('#sSearch button').off('click');
}
// Call our function when button clicked
$('#sSearch button').click(showSearch);
$(document).click(function (event) {
$target = $(event.target);
if(!$target.closest('#sSearch').length && $('#sSearch').not('.collapsed')) {
$('#sSearch').addClass('collapsed');
// Re-attach the function to button clicks, so page goes back to
// the initial state, before any button clicks
$('#sSearch button').click(showSearch);
}
});
Here's a working JSFiddle (sorry I switched from CodePen, I'm more used to it).
Alternatively, while the approach you've taken works fine, I'd maybe opt for something a little simpler. Rather than adding or removing event handlers based on user activity, I'd instead track the current state of the form and use that to work out what to do when a click happens.
We need some kind of variable to track the state ... but if you take a step back, you already have such a variable! The collapsed class tells us the current state of the page. You can use jQuery's .hasClass() method to check if the class is present or not, and that will tell us the state the page is currently in:
For clicks on the button, if the input currently has the collapsed class, you want to display it, so you prevent the submission and remove the class. If the input does not have that class, you don't do anything, and allow the submission to happen.
$('#sSearch button').on('click', function(event) {
if ($('#sSearch').hasClass('collapsed')) {
event.preventDefault();
$('#sSearch').removeClass('collapsed');
}
});
For clicks not on the button, when the input is shown, you want to hide it; when the input is hidden you do nothing.
$(document).on('click', function (event) {
$target = $(event.target);
if(!$target.closest('#sSearch').length && !$('#sSearch').hasClass('collapsed')) {
$('#sSearch').addClass('collapsed');
}
});
Here's another JSFiddle, using this different approach.
You can add a flag variable to determine if the input is shown or not. Also, you need to use .on("click") instead of .click() to handle live changes.
Here is the code:
let readySubmit = false;
$('#sSearch').on("click", "button", function(event) {
if (readySubmit == false) {
event.preventDefault();
$('#sSearch').removeClass('collapsed');
$('#sSearch button').off('click');
$('#sSearch button').html("Submit");
readySubmit = true;
}
});
$(document).click(function(event) {
$target = $(event.target);
if (!$target.closest('#sSearch').length && $('#sSearch').not('.collapsed')) {
$('#sSearch').addClass('collapsed');
$('#sSearch button').html("Open");
readySubmit = false;
}
});
#sSearch input {
position: absolute;
right: 40px;
width: 167px;
height: 38px;
padding-left: 0.75rem;
padding-right: 0.75rem;
border: 1px solid #ced4da;
transition-property: width, height, padding-left, padding-right;
transition-duration: 0.25s;
transition-timing-function: linear;
}
button {
transition: all 0.25s linear;
}
#sSearch.collapsed input {
width: 0;
padding-left: 0;
padding-right: 0;
border: none;
transition: all 0.25s linear;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="" id="sSearch" class="collapsed">
<input type="search" id="sSearch-Field" placeholder="Search">
<button type="submit">
Open
</button>
</form>
I have a disabled button that should become enabled when there is text in an input element. The code to enable/disable the button is in the onblur event of the input. My HTML consists of an input with id="in", a button with attribute disabled="disabled" and a span with id="sp".
$(document).ready(function(){
var count = 0;
$("#in").bind("blur",function(){
alert("blur");
if($("#in").attr("value").length > 0){
$("button")[0].disabled = false;
} else {
$("button")[0].disabled = true;
}
});
$("#in").bind("focusout",function(){
alert("focusout");
if($("#in").attr("value").length > 0){
$("button")[0].disabled = false;
} else {
$("button")[0].disabled = true;
}
});
$("button").click(function(){
count++;
$("#sp").text(count);
});
});
In IE 9, if I type text into the input element and click on the disabled button, the input's onblur fires, the button becomes enabled, and I get the button's click event.
However, in Chrome, when I type text into the input element and click on the disabled button, nothing at all happens.
Is there some property of the button I'm overlooking? I tried to get the focusout to fire, but I get the same result. I also get the same result using Firefox. Chrome seems to treat the disabled attribute more strictly than IE, but this is going to cause problems with our users. How can I get the onblur (or some equivalent) event to fire when I click off the input element onto a disabled button?
In Chrome, disabled buttons have all event listeners removed from them. Clicking, right clicking, selectstarting, etc. doesn't work on disabled buttons. This means that the focus doesn't leave the input when you click the disabled button. What you can do is manually disable the button via class="disabled", and adding some styles to make it look disabled. Here is an example of CSS you could use to make the button look disabled:
button.disabled,
button.disabled:hover,
button.disabled:active,
button.disabled:focus {
color:gray;
background:#EEE;
border:1px solid #AAA;
border-radius:3px;
outline:none;
}
I've made a JSFiddle that shows this here. Also note that I've changed the code that toggles the disabled class now, instead of the disabled attribute, and I've put an if statement in your button click event handler, so that it doesn't fire when the button is disabled.
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.
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).
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;