Prevent checkbox from ticking/checking COMPLETELY - javascript

I have been asked to disable the "ticking" of a checkbox. I am not being asked to disable the checkbox, but to simply disable the "ticking".
In other words, a user will think that a checkbox is tickable, but it is not. Instead, clicking on the checkbox will cause a modal dialog to appear, giving the user more options to turn on or off the feature that the checkbox represents. If the options chosen in the dialog cause the feature to be turned on, then the checkbox will be ticked.
Now, the real problem is that for a split second, you can still see that the checkbox is being ticked.
I have tried an approach like this:
<input type='checkbox' onclick='return false' onkeydown='return false' />
$('input[type="checkbox"]').click(function(event) {
event.preventDefault();
alert('Break');
});
If you run this, the alert will appear, showing that the tick is visible (the alert is just there to demonstrate that it still does get ticked, in production, the alert is not there). On some users with slower machines and/or in browsers with slow renderers/javascript, users can see a very faint flicker (the flicker sometimes lasts for half a second, which is noticeable).
A tester in my team has flagged this as a defect and I am supposed to fix it. I'm not sure what else I can try to prevent the tick in the checkbox from flickering!

From my point of view it is as simple as:
$(this).prop('checked', !$(this).prop('checked'));
Works both for checked and unchecked boxes

Try
event.stopPropagation();
http://jsfiddle.net/DrKfE/3/

Best solution I've come up with:
$('input[type="checkbox"]').click(function(event) {
var $checkbox = $(this);
// Ensures this code runs AFTER the browser handles click however it wants.
setTimeout(function() {
$checkbox.removeAttr('checked');
}, 0);
event.preventDefault();
event.stopPropagation();
});

This effect can't be suppressed I fear. As soon as you click on the checkbox, the state (and rendering) is changed. Then the event handlers will be called. If you do a event.preventDefault(), the checkbox will be reset after all the handlers are executed. If your handler has a long execution time (easily testable with a modal alert()) and/or the rendering engine repaints before reseting, the box will flicker.
$('input[type="checkbox"]').click(function(event) {
this.checked = false; // reset first
event.preventDefault();
// event.stopPropagation() like in Zoltan's answer would also spare some
// handler execution time, but is no more needed here
// then do the heavy processing:
alert('Break');
});
This solution will reduce the flickering to a minimum, but can't hinder it really. See Thr4wn's and RobG's answer for how to simulate a checkbox. I would prefer the following:
<button id="settings" title="open extended settings">
<img src="default_checkbox.png" />
</button>
document.getElementById("settings").addEventListener("click", function(e) {
var img = this.getElementsByTagName("img")[0]);
openExtendedSettingsDialog(function callbackTick() {
img.src = "checked_checkbox.png";
}, function callbackUntick() {
img.src = "unchecked_checkbox.png";
});
}, false);

It is very important to use return false at the end.
Something like this:
$("#checkbox").click((e) => {
e.stopPropagation();
return false;
});

Isn't is simpler ? :
<input type="checkbox" onchange="this.checked = !this.checked">

TL:DR;
HTML api's execute before JavaScript. So you must use JavaScript to undo HTML's changes.
event.target.checked = false
WHAT is the problem?
Strictly speaking: we cannot "stop" the checkbox from being ticked. Why not? Because "being ticked" exactly means that the DOM's, HTML <input> element has a checked property value of true or false, which is immediately assigned by the HTML api
console.log(event.target.checked) // will be opposite of the previous value
So it's worth explicitly mentioning this HTML api is called before scripts. Which is intuitive and should make sense, because all JavaScript files are themselves the assignment of a <script> element's attribute src, and the ancestral relationship in the DOM tree, between your <input> in question, and the <script> element running your JavaScript, is extremely important to consider.
HOW to get our solution
The HTML assigned value has not yet been painted before we have a chance to intercept the control flow (via JS file like jQuery), so we simply re-assign the checked property to a boolean value we want: false (in your case).
So in conclusion, we CAN, in-effect, "stop" the checkbox from being checked, by simply ensuring that the checked property is false on the next render and thus, won't see any changes.

Why not simply add a class in your CSS that sets pointer-events: none;?
Something like:
<style>
input.lockedCbx { pointer-events: none; }
</style>
...
<input type="checkbox" class="lockedCbx" tabindex=-1 />
...
You need the tabindex=-1 to prevent users from tabbing into the checkbox and pressing a space bar to toggle.
Now in theory you could avoid the class and use the tabindex=-1 to control the disabling as in:
<script>
input[type="checkbox"][tabindex="-1"] { pointer-events: none; }
</script>

With CSS, you can change the image of the checkbox. See http://ryanfait.com/resources/custom-checkboxes-and-radio-buttons/ and also CSS Styling Checkboxes .
I would disable the checkbox, but replace it with an image of a working checkbox. That way the checkbox doesn't look disabled, but won't be clickable.

Wrap the checkbox with another element that somehow blocks pointer events (probably via CSS). Then, handle the wrapper's click event instead of the checkbox directly. This can be done a number of ways but here's a relatively simple example implementation:
$('input[type="checkbox"').parent('.disabled').click( function() {
// Add in whatever functionality you need here
alert('Break');
});
/* Insert an invisible element that covers the checkbox */
.disabled {
position: relative;
}
.disabled::after {
content: "";
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Only wrapped checkboxes are "disabled" -->
<input type="checkbox" />
<span class="disabled"><input type="checkbox" /></span>
<input type="checkbox" />
<span class="disabled"><input type="checkbox" /></span>
<span class="disabled"><input type="checkbox" /></span>
<input type="checkbox" />
Note: You could also add the wrapper elements programmatically, if you would like.

Sounds to me like you are using the wrong interface element, a more suitable one would be a button that is disabled by default, but enabled when that option is available. The image displayed can be whatever you want.
<button disabled onclick="doSomething();">Some option</button>
When users have selected that feature, enable the button. The image on the button can be modified by CSS depending on whether it's enabled or not, or by the enable/disable function.
e.g.
<script type="text/javascript">
function setOption(el) {
var idMap = {option1:'b0', option2: 'b1'};
document.getElementById(idMap[el.value]).disabled = !el.checked;
}
</script>
<div><p>Select options</p>
<input type="checkbox" onclick="setOption(this);" value="option1"> Option 1
<br>
<input type="checkbox" onclick="setOption(this);" value="option2"> Option 2
<br>
</div>
<div>
<button id="b0" onclick="alert('Select…');" disabled>Option 1 settings</button>
<button id="b1" onclick="alert('Select…');" disabled>Option 2 settings</button>
</div>

The Event.preventDefault method should work for change, keydown, and mousedown events, but doesn't in my testing.
My solution to this problem in a Mozilla Firefox 53.0 extension was to toggle an HTML class that enabled/disabled the CSS declaration pointer-events: none being applied to the checkbox. This addresses the cursor-based case, but not the key-based case. See https://www.w3.org/TR/SVG2/interact.html#PointerEventsProp.
I addressed the key-based case by adding/removing an HTML tabindex="-1" attribute. See https://html.spec.whatwg.org/multipage/interaction.html#attr-tabindex.
Note that disabling pointer-events will disable your ability to trigger CSS cursors on hover (e.g., cursor: not-allowed). My checkbox was already wrapped in a span element, so I added an HTML class to that span element which I then retargeted my CSS cursor declaration onto.
Also note that adding a tabindex="-1" attribute will not remove focus from the checkbox, so one will need to explicitly defocus it by using the HTMLElement.blur() method or by focusing another element to prevent key-based input if the checkbox is the active element at the time the attribute is added. Whether or not the checkbox is the focused element can be tested with my_checkbox.isEqualNode(document.activeElement).

Simply revert the value back
$('input[type="checkbox"]').on('change', function(e) {
if (new Date().getDate() === 13) {
$(this).prop('checked', !$(this).prop('checked'));
e.preventDefault();
return false;
}
// some code here
});

Add this to click event in js file
event.stopPropagation();

$('#term-input').on('change click',function (e){
e.preventDefault();
})
works for me

Related

Am I using `button.disabled = true;` incorrectly?

I'm trying to build an interaction in Animate CC that plays movie clips, and the buttons disappear after they are clicked.
I'm trying to disable the other buttons temporarily while the movie clip plays over the main background, but it's not playing nice.
A code Snippet of the click handler:
exportRoot.btn_cook.addEventListener("click", cook_clickHandler.bind(this));
function cook_clickHandler(){
exportRoot.cook.gotoAndPlay(1); //play the info clip
exportRoot.btn_cook.visible = false; //hide button for no replays
disableAll();
}
disableAll(); does the following for each button on the canvas:
if(exportRoot.btn_receive.visible == true){
exportRoot.btn_receive.disabled = true;
}
I'm having some trouble trying to figure out how to use this properly. When I run through the interaction, I am still able to click on the buttons, even though I supposedly disabled them?
This demo won't load sound on GitHub, but it works otherwise. Click here to see it.
I had the same problem so I have another way to do it:
You can try to remove the eventListener click, like this:
if(!exportRoot.btn_receive.hasEventListener("click")){
exportRoot.btn_receive.removeEventListener("click", cook_clickHandler);
}
When u want this to be enabled again, add the eventListener.
The disabled attribute is a Boolean attribute. That means that just the presence of it is enough to cause the element to become disabled. It makes no difference what you set the value to. You need to remove the attribute from the element to remove the disabled effect.
Removing the event listener treats the symptom, it doesn't get to the heart of the issue.
Also (FYI), the visibility property gets values of "visible" or "hidden", not true or false.
Here is a simple example of how to apply and disable (no pun intended) the disabled attribute:
btnToggle.addEventListener("click", function(){
var elems = document.querySelectorAll(".disableEnable");
// Loop through each element in the class
elems.forEach(function(element){
// Check to see if the first element has the disabled attribute
// the value of the attribute doesn't matter. If the attribute
// is present, the element is currently disabled.
if(element.getAttribute("disabled")){
// Element is disabled, so enabled it by removing
// the attribute (not by setting a value)
element.removeAttribute("disabled");
} else {
// Element is enabled, so disable it by adding the disabled
// attribute. Again, the value doesn't matter, but convention
// says that we set a value of "disabled" to convey that it is
// a boolean attribute.
element.setAttribute("disabled", "disabled");
}
});
});
<button id="btnToggle">Disable / Enable</button>
<button class="disableEnable">Test Button</button>
<input class="disableEnable">
<input type="text" class="disableEnable">

ng-mouseover on disabled button in Angularjs

I want to use mouseover when the button is disabled. In the below code mouseover will work if ng-disabled="false" but it won't work if ng-disabled="true".
<body ng-app="ngAnimate">
<button ng-disabled="true" ng-mouseover="show=true" ng-mouseleave="show = false">
Mouseover
</button>
<div>
Show:
<span class="test" ng-show="show">
I show up when your mouse enter on button
</span>
</div>
</body>
It's not possbile. Actually it has nothing to do with Angular. It's expected behaviour when browsers are not supposed to fire onmouseover, onclick, etc. events on disabled form controls. So you can't do it directly.
Can't do it directly - meaning, that you can bind mouseover even to wrapping container which would not have this limitation. Then you would need to control action and proceed only if disabled flag is true or false if you need.
That being said, you should probably not try to workaround this behaviour. Form UX perspective disabled control should not be interaction-able, after all that's what disabled means.
I recently faced a similar problem where i disable a submit button on a form unless the form is valid. When the user hover over the disabled button, I wanted all required fields to get a different color.
I solved this using a html structure like this:
<div ng-class="{error: showError}">
<div disabled-wrapper ng-mouseenter="checkValid()" ng-mouseleave="showError = false">
<div><button ng-disabled="!valid">Next</button></div>
</div>
</div>
And css like this:
[disabled-wrapper] {
position: relative;
z-index: 0;
}
[disabled-wrapper] [disabled] {
position: relative;
z-index: -1;
}
And controller function:
$scope.checkValid = function() {
$scope.showError = !$scope.valid;
}
// I have more logic regarding validity of form.
// I am not sure why the div within the wrapper is needed (but it is).
// The positioning and z-index of the wrapper prevents any parent element with back-ground color from overshadowing the disabled button.

Target Previous Input Field

I am attempting to target the previous input field of a form element that is in an accordion. I have tried several ways to target the .image-url field but I am having trouble with targeting just this one field within the accordion. This may be a simple task but I cannot get this thing to work. Any help would be greatly appreciated.
HTML
<form>
<input class="image-url" type="text" />
<input class="button" type="button" />
</form>
JS
$('form .button').click(function() {
// do stuff
uploader.on('select', function() {
$(this).prev().val('text to put');
}
}
This is what I have right now and I cannot get it to work.
this within the uploader.on callback probably isn't the button. Remember the button and then use it in the callback:
$('form .button').click(function() {
var btn = $(this);
// do stuff
uploader.on('select', function() {
btn.prev().val('text to put');
}
});
Side note: Whenever I see an event handler hooked up from within another event handler, it raises a flag for me. If the button is clicked twice, you'll end up with two handlers on uploader for the select event. You might want to check whether that's really what you want...
Side note 2: CSS selectors can do more than just ids and classes, you may not need that class="button" on the button. You can select it via form input[type=button] (in your CSS for styling, and in a jQuery $() call and similar to locate it).

Prevent nested label link from following, but change checkbox state

I have an issue where I have the following markup:
<input type="checkbox" id="foo" />
<label for="foo">
<a href="http://www.google.com">
Checkbox text
</a>
</label>
The label has a nested anchor in case the user doesn't have javascript enabled, and in which case they will follow the link when clicking the label.
I have the following javascript/jQuery to prevent the link click and to show an alert when the checkbox state has changed:
$(function(){
$("label a").click(function(e){
e.preventDefault();
});
$("#foo").change(function(){
alert("checkbox changed");
});
});
-- See Example --
However when clicking the label the checkbox checked state isn't changed.
I'm aware I could hack the code and try and emulate the native browser functionality by adding code to set the checked status, however I would prefer to use the native functionality than emulate it.
How can I get the checkbox to change state without following the link, and without setting the checked state using javascript?
bit confused here and without setting the checked state using javascript?...
but i think you are talking about trigger()...
$("label a").click(function(e){
var $foo = $("#foo");
$foo.attr("checked", !$foo.attr("checked"));
$foo.trigger('change');
return false;
});
fiddle

Remove disabled attribute onClick of disabled form field

I have a form field that starts out disabled and has an onClick to enable it. The onClick doesn't fire (at least in FF) nor does a simple alert(1);.
The hacky version is to show a fake form field in its place that "looks" like it's disabled (grayed out style) and onClick, hide it and show the correct field enabled, but that's ugly.
Example Code
This works:
<input type="text" id="date_end" value="blah" onClick="this.disabled=true;">
This works:
<label for="date_end_off" onClick="document.getElementById('date_end').disabled=false">Test</label>
<input type="text" id="date_end" value="blah" onClick="alert(1);" disabled>
This fails:
<input type="text" id="date_end" value="blah" onClick="alert(1);" disabled>
This fails:
<input type="text" id="date_end" value="blah" onClick="document.getElementById('date_end').disabled=false" disabled>
I came across this thread in another forum so I assume I'll have to go about it a different way.
http://www.webdeveloper.com/forum/showthread.php?t=186057
Firefox, and perhaps other browsers,
disable DOM events on form fields that
are disabled. Any event that starts at
the disabled form field is completely
canceled and does not propagate up the
DOM tree. Correct me if I'm wrong, but
if you click on the disabled button,
the source of the event is the
disabled button and the click event is
completely wiped out. The browser
literally doesn't know the button got
clicked, nor does it pass the click
event on. It's as if you are clicking
on a black hole on the web page.
Work around:
Style the date fields to look as if
they are disabled.
Make a hidden "use_date" form field
with a bit value to determine
whether to use the date fields during processing.
Add new function to onClick of the date fields which will
change the style class to appear
enabled and set the "use_date" value
to 1.
Use readonly instead of disabled
For checkboxes at least, this makes them look disabled but behave normally (tested on Google Chrome). You'll have to catch the click and prevent the default action of the event as appropriate.
Using jQuery, I attach an event handler to the parents of my input controls.
<script type="text/javascript">
$(function() {
// disable all the input boxes
$(".input").attr("disabled", true);
// add handler to re-enable input boxes on click
$("td:has(.input)").click(function() {
$(".input", this).removeAttr("disabled");
});
});
</script>
All of my input controls have the class "input" and they exist in their own table cells. If you at least wrapped your input tags in a div, then this should work without a table as well.
Citing Quirksmode.org:
"A click event on a disabled form field does not fire events in Firefox and Safari. Opera fires the mousedown and mouseup events, but not the click event. IE fires mousedown and mouseup, but not click, on the form. All these implementations are considered correct."
Quirksmode's compatibility table is great to find out more about such problems.
I recently had a very similar problem and solved it by placing the input in a div and moving the onClick to the div.
<div onClick="myEnableFunction('date_end');">
<input type="text" id="date_end" value="blah" disabled>
</div>
Enabling a disabled element on click kind of defeats the purpose of disabling, don't you think? If you really want the behavior you're describing, just style it 'disabled' and remove those styles on click.
Don't implement the logic of the onClick event in the onClick's value of the input field. That's probably why it's not working in Firefox. Instead define a function as the onClick's value. For example:
<input type="text" id="date_end" value="blah" onClick="doSomething()" disabled>
<script type="text/javascript">
function doSomething()
{
alert("button pressed");
}
</script>
It will also be worth looking into JQuery. You can use it to add or remove attributes from elements and all kinds of other stuff. For instance you can remove the disabled from the the input field by writing a function like this:
<script type="text/javascript">
function doSomething()
{
alert("button pressed");
$("#date_end").removeAttr('disabled'); //removes the disabled attribut from the
//element whose id is 'date_end'
}
</script>
OR you can add it as follows:
$("#date_end").attr('disabled','true');
The Jquery site is here
You can add a div over the input that is disabled: check it out
<div onclick="javascript:document.forma.demo1.disabled=false;" style="border:0px solid black; padding:00px;">
<input type=text name="demo1" disabled style="width:30;">
</div>
In order to enable a disabled element on the client side, lets say in response to a checkbox checked or something, I ended up having to use a combination of JS and jQuery, see below:
//enable the yes & no RB
function enable()
{
var RBNo = "rbnBusinessType";
var RBYes = "rbnBusinessType";
//jQuery approach to remove disabled from containing spans
$("#" + RBYes).parent().removeAttr('disabled');
$("#" + RBNo).parent().removeAttr('disabled');
//enable yes and no RBs
document.getElementById(RBYes).disabled = false;
document.getElementById(RBNo).disabled = false;
}
After postback then, you'll need to access the request like the following in order to get at the values of your client side enabled elements:
this._Organization.BusinessTypeHUbZoneSmall = Request.Params["rbnBusinessTypeHUbZoneSmall"] == rbnBusinessTypeHUbZoneSmallYes.ID;
Inspiration taken from:
https://stackoverflow.com/questions/6995738/asp-javascript-radiobutton-enable-disable-not-included-in-postback-ajax for more information
If you simply want to prevent the user from typing data in your field, but instead want the field to populate on an event, my hack solution was to not disable the input field at all, but instead after running my onclick or onfocus functions, to call blur() so the user can not edit the field.

Categories