Cannot programmatically select radio button if preventDefault() called - javascript

I've got a 'catch 22' in Chrome. I cannot programmatically select a radio button within a click event if any other function bound to the same event makes a call to preventDefault().
For example, I have a radio button with a parent element bound to a click event in which preventDefault() is called. If the radio button is clicked directly it is not checked. This is to be expected. However, I actually need the radio button to be selected so within code I attempt to check it in another function bound to the click event: $(this).prop('checked', true);.
Oddly, this doesn't work and I cannot remove the call to preventDefault() or disable propagation because it is in third party code that I need to run.
Is this a bug? Any suggested workarounds?
Here is an example:
http://jsfiddle.net/LnLuk4st/
UPDATE:
I have tried #RGraham's suggestion. His example clearly works, but oddly it does not work in the context of my code. #RGraham's code had a syntax error which made it appear to be working.
Here's some context:
// Remember kendo tab
$(".k-tabstrip").each(function () {
var $tabStrip = $(this);
var $tabs = $tabStrip.find(".k-tabstrip-items .k-item");
var tabCookie = "Current_Tab_" + $tabStrip.attr("id");
// On tab change, set cookie
$tabs.click(function () {
createCookie(tabCookie, $(this).attr("aria-controls"), 1);
$tabStrip.parent().css({ 'min-height': $tabStrip.parent().height() });
if ($(this).is('input')) { // Doesn't eval to true, 'this' is always a '.k-item'.
$(this).prop("checked", true);
} else {
// Never works if the input is clicked directly
$(this).find('input').prop("checked", true);
}
});
// #RGraham's suggestion...
$tabs.on('click', 'input', function() {
$(this).prop("checked", true); // Line reached but doesn't work either :(
});
// If cookie set, select tab
var tab = readCookie(tabCookie);
if (tab) {
$tabs.each(function () {
if ($(this).attr("aria-controls") == tab) {
$(this).click();
}
});
}
});

I still believe this behaviour to be a bug but I have found a workaround.
Capture the click of the radio button directly, prevent propagation, then programmatically click the parent of the radio button. This allows the third party code to run without applying preventDefault to the radio button.
// preventDefault bug fix.
$tabs.find("input").click(function (e) {
e.stopPropagation();
$(this).parent().click();
});

Related

Stop onclick method running with jQuery

I have a button similar to below
<button id="uniqueId" onclick="runMethod(this)">Submit</button>
What I'm trying to do is stop the runMethod from running, until after I've done a check of my own. I've tried using the stopImmediatePropagation function, but this doesn't seem to have worked. Here's my jQuery:
$j(document).on('click', '#uniqueId', function(event) {
event.stopImmediatePropagation();
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Note: runMethod basically validates the form, then triggers a submit.
What you want to do, especially in the way that you want to do it, requires a some sort of workaround that will always be a bit fiddly. It is a better idea to change the way the button behaves (e.g. handle the whole of the click event on the inside of the jQuery click() function or something along those lines). However I have found sort of a solution for your problem, based on the assumption that your user will first hover over the button. I am sure you can extend that functionality to the keyboard's Tab event, but maybe it will not work perfectly for mobile devices' touch input. So, bear in mind the following solution is a semi-complete workaround for your problem:
$(document).ready(function(){
var methodToRun = "runMethod(this)"; // Store the value of the onclick attribute of your button.
var condition = false; // Suppose it is enabled at first.
$('#uniqueId').attr('onclick',null);
$('#uniqueId').hover(function(){
// Check your stuff here
condition = !condition; // This will change to both true and false as your hover in and out of the button.
console.log(condition); // Log the condition's value.
if(condition == true){
$('#uniqueId').attr('onclick',methodToRun); // Enable the button's event before the click.
}
},
function(){
console.log('inactive'); // When you stop hovering over the button, it will log this.
$('#uniqueId').attr('onclick',null); // Disable the on click event.
});
});
What this does is it uses the hover event to trigger your checking logic and when the user finally clicks on the button, the button is enabled if the logic was correct, otherwise it does not do anything. Try it live on this fiddle.
P.S.: Convert $ to $j as necessary to adapt this.
P.S.2: Use the Javascript console to check how the fiddle works as it will not change anything on the page by itself.
Your problem is the submit event, just make :
$('form').on('submit', function(e) {
e.preventDefault();
});
and it works. Don't bind the button click, only the submit form. By this way, you prevent to submit the form and the button needs to be type button:
<button type="button" .....>Submit</button>
Assuming there's a form that is submitted when button is clicked.
Try adding
event.cancelBubble();
Hence your code becomes:
$j(document).on('click', '#uniqueId', function(event) {
// Don't propogate the event to the document
if (event.stopPropagation) {
event.stopPropagation(); // W3C model
} else {
event.cancelBubble = true; // IE model
}
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Your code is mostly correct but you need to remove J:
$(document).on('click', '#uniqueId', function(event) {...
You also need to remove the onClick event from the inline code - there's no need to have it there when you're assigning it via jQuery.
<button id="uniqueId">Submit</button>

Validation using checkbox

I am using jQuery trying to validate that a checkbox has been checked before allowing a user to click on a 'Proceed' button.
The 'Proceed' button is set 'Enable = false' when the page loads.
So far I have tried :
// On check of the accept terms checkbox
$(".chkTandCs").change(function () {
// If checked, enable the Continue button, else, disable it.
if ($(this).is(":checked")) {
$(".lbnAcceptCurrent").removeAttr('disabled');
}
else {
$(".lbnAcceptCurrent").attr("disabled", "disabled");
}
});
This hasn't worked.
The checkbox and 'Proceed' button are inside a modal that opens when a different button has been clicked.
All help very much appreciated
Use prop() instead
$(".chkTandCs").change(function () {
$(".lbnAcceptCurrent").prop('disabled', !this.checked);
});
If the modal generates the markup dynamically, you'll need to delegate
$(document).on('change', '.chkTandCs', function () {
$(".lbnAcceptCurrent").prop('disabled', !this.checked);
});
and replace document with the closest static parent element of the modal

Return false doesn't cancel radio buttons click in Chrome when no other value selected

I'm trying to cancel a radio button click. I have a jquery click handler like this:
$("#myList").on("click","input", function(){
return false;
});
This works fine when there is already a selected value. But if I click a radio button from a group that has no selected value, the return false does not work, and the element that I clicked actually gets selected.
Any clues?
Edit:
Here is the fiddle demonstrating the problem:
http://jsfiddle.net/SFZMm/2/
Edit2:
Just found out this only happens on chrome :( Firefox and IE work as expected. Maybe a workaround?
Here, try this JS_FIDDLE-DEMO
It detects the click on the parent container. Not the radio button it self.
//listen to click on parent div,span,li for example.
$("#myList-parent").click(function(){
alert('You clicked radio!');
//Now put your logic here. I decide based on the radio button value.
if($('input:radio[name=type]:checked').val() == "UnSelectable"){
alert($('input:radio[name=type]:checked').val());
return false;
}
});
Update (work around for Chrome): JS-FIDDLE-DEMO
It seems Chrome has issues with on click so replace it with on mousedown (or use both?):
$("input").on("mousedown",function(e) {
e.preventDefault();
if ($(this).is(':checked')) {
alert('This radio button was checked in mousedown');
} else {
alert('This radio button was not checked in mousedown');
}
});
Use change methods for input elements instead of click.
$("#myList").on("change","input", function(e){
if(something){
e.preventDefault();
} else{
//for test
alert('not true');
}
});

Detecting form changes using jQuery when the form changes themselves were triggered by JS

I have a list of radio buttons that I can toggle "yes" or "no" to using Javascript.
$(document).ready(function(){
$('#select-all').click(function(){
$('#notifications .notif-radio').each(function(){
$('input[type="radio"]', this).eq(0).attr('checked', true);
$('input[type="radio"]', this).eq(1).attr('checked', false);
});
});
$('#deselect-all').click(function(){
$('#notifications .notif-radio').each(function(){
$('input[type="radio"]', this).eq(0).attr('checked', false);
$('input[type="radio"]', this).eq(1).attr('checked', true);
});
});
});
this works just fine. Now I have a separate piece of code that detects when a user has changed something, and asks them if they want to leave the page.
var stay_on_page;
window.onbeforeunload = confirm_exit;
$('.container form input[TYPE="SUBMIT"]').click(function(){
stay_on_page = false;
});
$('#wrapper #content .container.edit-user form').change(function(){
stay_on_page = true;
});
function confirm_exit()
{
if(stay_on_page){ return "Are you sure you want to navigate away without saving changes?"; }
}
The problem is that if the user uses the first piece of functionality to toggle all radio buttons one way or another. The JS detecting form changes doesn't see that the form was changed. I have tried using .live, but to no avail. Anyone have any ideas?
I do something similar to this by adding change() (or whatever's appropriate, click() in your case I suppose) event handlers which set either a visible or hidden field value, then check that value as part of your onbeforeunload function.
So, my on before unload looks like:
window.onbeforeunload = function () {
if ($('#dirtymark').length) {
return "You have unsaved changes.";
}
};
And, or course, dirtymark is added to the page (a red asterisk near the Save button), when the page becomes dirty.

Looking for a better workaround to Chrome select on focus bug

I have the same problem as the user in this question, which is due to this bug in Webkit. However, the workaround provided will not work for my app. Let me re-state the problem so that you don't have to go read another question:
I am trying to select all the text in a textarea when it gets focus. The following jQuery code works in IE/FF/Opera:
$('#out').focus(function(){
$('#out').select();
});
However, in Chrome/Safari the text is selected--very briefly--but then the mouseUp event is fired and the text is deselected. The following workaround is offered in the above links:
$('#out').mouseup(function(e){
e.preventDefault();
});
However, this workaround is no good for me. I want to select all text only when the user gives the textarea focus. He must then be able to select only part of the text if he chooses. Can anyone think of a workaround that still meets this requirement?
How about this?
$('#out').focus(function () {
$('#out').select().mouseup(function (e) {
e.preventDefault();
$(this).unbind("mouseup");
});
});
The accepted answer (and basically every other solution I found so far) does not work with keyboard focus, i. e. pressing tab, at least not in my Chromium 21. I use the following snippet instead:
$('#out').focus(function () {
$(this).select().one('mouseup', function (e) {
$(this).off('keyup');
e.preventDefault();
}).one('keyup', function () {
$(this).select().off('mouseup');
});
});
e.preventDefault() in the keyup or focus handler does not help, so the unselecting after a keyboard focus seems to not happen in their default handlers, but rather somewhere between the focus and keyup events.
As suggested by #BarelyFitz, it might be better to work with namespaced events in order to not accidentally unbind other event handlers. Replace 'keyup' with 'keyup.selectText' and 'mouseup' with 'mouseup.selectText' for that.
Why not simply:
$('#out').focus(function(){
$(this).one('mouseup', function() {
$(this).select();
});
});
Seems to work in all major browsers...
A very slightly different approach would be to separate the focus event from the mouse sequence. This works really nicely for me - no state variables, no leaked handlers, no inadvertent removal of handlers, and it works with click, tab, or programmatic focus. Code and jsFiddle below -
$('#out').focus(function() {
$(this).select();
});
$('#out').on('mousedown.selectOnFocus', function() {
if (!($(this).is(':focus'))) {
$(this).focus();
$(this).one('mouseup.selectOnFocus', function(up) {
up.preventDefault();
});
}
});
https://jsfiddle.net/tpankake/eob9eb26/27/
Make a bool. Set it to true after a focus event and reset it after a mouse up event. During the mouse up, if it's true, you know the user just selected the text field; therefore you know you must prevent the mouse up from happening. Otherwise, you must let it pass.
var textFieldGotFocus = false;
$('#out').focus(function()
{
$('#out').select();
textFieldGotFocus = true;
});
$('#out').mouseup(function(e)
{
if (textFieldGotFocus)
e.preventDefault();
});
$(document).mouseup(function() { textFieldGotFocus = false; });
It's important that you put the mouseup listener that resets the variable on document, since it's not guaranteed that the user will release the mouse button over the text field.
onclick="var self = this;setTimeout(function() {self.select();}, 0);"
Select the text before putting the focus on the input box.
$('#out').select().focus();
digitalfresh's solution is mostly there, but has a bug in that if you manually trigger .focus() using JS (so not using a click), or if you tab to the field, then you get an unwanted mouseup event bound - this causes the first click that should deselect the text to be ignored.
To solve:
var out = $('#out');
var mouseCurrentlyDown = false;
out.focus(function () {
out.select();
if (mouseCurrentlyDown) {
out.one('mouseup', function (e) {
e.preventDefault();
});
}
}).mousedown(function() {
mouseCurrentlyDown = true;
});
$('body').mouseup(function() {
mouseCurrentlyDown = false;
});
Note: The mouseup event should be on body and not the input as we want to account for the user mousedown-ing within the input, moving the mouse out of the input, and then mouseup-ing.
tpankake's answer converted to a reusable jQuery function..
(If you upvote this, please also upvote his answer)
Load the following AFTER loading the jQuery library:
$.fn.focusSelect = function () {
return this.each(function () {
var me = $(this);
me.focus(function () {
$(this).select();
});
me.on('mousedown.selectOnFocus', function () {
var me2 = $(this);
if (me2.is(':focus') === false) {
me2.focus();
me2.one('mouseup.selectOnFocus', function (up) {
up.preventDefault();
});
}
});
});
};
Use it like this:
$(document).ready(function () {
// apply to all inputs on the page:
$('input[type=text]').focusSelect();
// apply only to one input
$('#out').focusSelect();
});

Categories