Radio button group - change events for buttons become deselected? - javascript

Let's say I have a group of two radio buttons:
<input type="radio" name="radioButtonGroup" value="button1" checked="true"/>
<input type="radio" name="radioButtonGroup" value="button2"/>
It seems that clicking the second button triggers an event handler on that button only. However, the first button does become deselected, and visually does change. Can anyone verify that events are fired only on the button that was selected, and not any of the other buttons in the group which become deselected as a result of the click? Any clever ways to watch a radio button for a deselecting event?

Although it cannot be confirmed, but the event change triggers don't happen on the entire group.
If you want that to happen, you can do it using various JS libraries like jQuery, YUI, etc. or even plain javascript, as follows:
function buttonGroupChange(){
var radioElements = document.getElementsByName("radio_group_name");
for(var i = 0; i < radioElements.length; i++){
if(radioElements[i].checked == true){
//do something
}
else{
//do something
}
}
}
This function can be called on the onClick or the onChange event.
I hope that solves your problem.

Firstly, it is important to note that a "Click" event on any of the radios fires AFTER the "checked" value is already updated. This is important - because it means you can't detect the previous item once the event is already fired. If you Cancel the event, you are actually changing the value BACK - not stopping it initially. This is important to how you approach the problem.
Example:
<input type="radio" name="radioButtonGroup" value="button1" checked="true"/>
<input type="radio" name="radioButtonGroup" value="button2"/>
// At this point, the ':checked' item is button1.
$('input[type=radio]').bind('click', function (ev) {
// If you click on button2 - by this point, the ':checked' item is already button2.
ev.preventDefault(); // These two lines will stop the radio from actually
ev.stopPropagation(); // changing selection.
// At this point, the ':checked' item is set BACK to button1.
});
Because of this, the easiest solution is to track the "last" selected item in a closure alongside your event handlers, as follows:
<input type="radio" name="radioButtonGroup" value="button1" checked="true"/>
<input type="radio" name="radioButtonGroup" value="button2"/>
<script type="text/javascript">
var $last = $('[name=radioButtonGroup]:checked');
// Select the radio buttons as a group.
var $radios = $('[name=radioButtonGroup]').bind('change', function (ev) {
// Click event handler
var $clicked = $(ev.target); // This is the radio that just got clicked.
$last.trigger('unclick'); // Fire the "unclick" event on the Last radio.
$last = $('[name=radioButtonGroup]:checked'); // Update the $last item.
// Should see the clicked item's "Value" property.
console.log("Clicked " + $clicked.attr('value'), $clicked, ev);
}).bind('unclick', function (ev) {
// Handler for our new "unclick" event.
// - fires whenever a radio loses focus.
var $unclicked = $(ev.target); // The radio losing it's checked status.
// Should see the unclicked item's "Value" property.
console.log("Unclicked " + $unclicked.attr('value'), $unclicked, ev);
});
</script>
For a working example, see:
http://jsfiddle.net/TroyAlford/wvrtC/

I can't confirm that an event is only fired for the selected button, but if you needed to do something with the button that was just deselected, the following would work:
$(document).ready(function(){
var selectedRadio = null;
$("input:radio").change(function(){
if(selectedRadio != null){
alert(selectedRadio.val());
}
selectedRadio = $(this);
});
});
In action here.
If you need to keep track of multiple groups of radio buttons, you could do it with an array of currently selected buttons and match within that array when a change is detected.

The simple nature of the radio button set is that only one button can be selected at a time. Selecting a button automatically means the others are not selected, but there is no specific action for deselecting. Therefore, you only need to worry about the one event, because it affects all the buttons in the set at one time.
If you would like to use an element that allows for multiple selections try checkboxes.

Related

onClick vs onFocus on input element

To move focus on the end of inputs when user click the input box,
I use something like this,
$(function() {
$('#test-input').on('click', function(evt) {
$target = $(evt.target);
var val = $target.val();
$target.val('').val(val);
});
}())
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="test" id="test-input" value="abcdefgh" />
But if I change the 'click' to 'focus', it doesn't work.
$(function() {
$('#test-input').on('focus', function(evt) {
$target = $(evt.target);
var val = $target.val();
$target.val('').val(val);
});
}())
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="test" id="test-input" value="abcdefgh" />
How different onClick and onFocus actions in that case?
There's some differences:
onClick: This event is fired whenever the user clicks in an object, like a button, an image, an input... After the click, then comes the:
onFocus: This event is fired when an element is selected, it doesn't need to be clicked, it can be done programmatically, calling .focus() or using the Tab key, for example. Also, using onfocus instead of onclick, can help to avoid bubbling.
To finish, use the snippet below (I added more inputs, cycle through it with TAB (or click too), you'll see the caret going to end on all of then.
Why I added a timeout?
Chrome Browser has an odd quirk where the focus event fires before the cursor is moved into the field, so, the event must wait to the cursor to get there before moving it to the end.;
$(function() {
$('.test-input').on('focus', function(evt) {
that = this;
setTimeout(function() {
that.selectionStart = that.selectionEnd = 10000;
}, 1);
});
}())
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="test" class="test-input" value="abcdefgh" />
<input type="text" name="test" class="test-input" value="a1b2c3" />
<input type="text" name="test" class="test-input" value="abcdefghijklmnop" />
Extra:
If you are programming just for mobiles, will be nice to take a look at touchEvents (https://developer.mozilla.org/pt-BR/docs/Web/Events/touchstart)
This should be working just fine the first time you click on the textbox. This is when the focus event is triggered, since you're actually 'focusing on' the item. From then on, until you click anywhere outside the element, your item will already have the focus and therefore will not execute the onfocus event.
The main difference is focus event call any time when you will focus on input field like if you use tab button and focused on input field but in case of click you need to click on input field.
I think that it has to do with the fact that the code executed at the click is executed before focusing on the input and affecting a position to the cursor.
On the other hand, when you listen to the focus event, the cursor has already a position and stays at this position.
That's pure personal theory. However, if you want to make it work, I found a great solution that works in Chrome on this question: Use JavaScript to place cursor at end of text in text input element
You need to clear the value of the input, wait for one millisecond, and reapply the value:
$(function() {
$('#test-input').on('focus', function(evt) {
$target = $(evt.target);
var val = $target.val();
$target.val('');
setTimeout(() => {
$target.val(val)
},1)
});
})

Why OnChange Event is not Dispatched When Target Is Manually Set

I'm confused on how JavaScript handles Change Events and am looking for some insight.
Let's say we have two HTML controls; a Checkbox and a Button and I want to use JS to display a message that says how many times the Checkbox has changed from checked to not-checked.
<input type="checkbox" id="cb" />
<button id="btn">Change Checkbox</button>
<div id="msg"></div>
The JS can look something like this:
var count = 0;
var cb = document.getElementById("cb");
var btn = document.getElementById("btn");
var msg = document.getElementById("msg");
cb.addEventListener("change", cb_onChange);
btn.addEventListener("click", btn_onClick);
// Change the state of the Checkbox when user clicks the Button
function btn_onClick() {
cb.checked = !cb.checked;
}
// The state of the Checkbox has changed, so increment the change count and display it
function cb_onChange() {
msg.innerHTML = "Checkbox changed " + count+++" times";
}
Test it out here http://jsfiddle.net/26RWh/
Notice that the OnChange event of the Checkbox is NOT dispatched when the Checkbox is programmatically set at cb.checked = !cb.checked. - i.e. The cb_onChange listener is only executed if/when the user manually clicks the Checkbox.
How come the OnChange event isn't fired when I change the state in code?
This is the way events on input-elements work in javascript.
If you want the callback to be executet you need to manually fire the change-event on the checkbox.
There are questions about this:
do it in pure JavaScript
and with help of jquery
when the browser identifies a change event in checkbox, it sets the checked propery to !checked and calls the subscribed functions which you can assume happens in one function(f1) and which is called when the event occurs. In this case you are not calling the function f1 but just setting the property.

prevent immediate Radio :checked property on click event

I have a click event handler attached to a group of radio inputs, and want to see if I am clicking on the radio button that is already selected (has property 'checked' set). I figured the event handler would act in a daisy chained fashion (first calling my event handler on the click and then continuing down the chain to the default behavior of the click). Apparently this is not the case, because when I evaluate if the property 'checked' is true on the radio button I just clicked, it always returns true in my click event handler.
The click has already been processed by the default behavior and has already applied the 'checked' property to the radio button I just clicked. Again, I figured my click event handler would be processed prior to that default behavior. What's even more odd is that even when I prevent the default behavior, it still returns true for the 'checked' property. I assume this is because the 'checked' property is being processed by the 'change' event, so preventing the default behavior on my click event handler is not affecting anything.
$("input[type='radio']").click(function(e) {
e.preventDefault();
alert($(this).prop("checked")); // always returns true; i want prop value immediately prior to click
});
How can I achieve what I'm after? That is, to see whether or not the radio button that was just clicked on was the one already checked. Thanks.
Based on the response of #Jeffman , I was able to get something to work for what I needed to do. I have custom buttons, only one of which can be selected (hence the use of radio buttons). However, if you click on the one that's already selected, it should deselect and select the default value instead.
Things I had to do. Handle mousedown events on the radio labels. If I am clicking on the already selected radio, set the default button to be 'checked'. Else I just select the button that has been clicked on. I had to disable the 'click' event on these buttons, as that would override my irregular handling of the radio buttons (for some reason the selection would snap back to the one that was clicked when I overrode it and chose the default one manually). This also meant I would need to manually trigger the change event, as I do the custom radio button styling there.
$(".radios > label").mousedown(function(e) {
var l = $(this); // label
var t = l.parent(); // container for radio group
var i = l.find("input"); // input element of this label
if(i.prop("checked")) { // clicking on the already selected button
t.find(".default_radio input").prop("checked", true).trigger("change");
} else {
i.prop("checked", true).trigger("change");
}
}).bind('click',false);
$("input[type='radio']").change(function(e) {
// style the buttons here
});
Save radio status before click via mousedown
var was_checked;
$( "#radio" ).mousedown(function() {
was_checked = $(this)[0].checked;
});
$( "#radio" ).click(function() {
$(this).attr('checked', !was_checked);
});
i think you should also return false. not only preventDefault
Here is a sample code that would do the trick
<script>
$(function() {
var radios = {};
$("input[type='radio']").each(function() {
radios[$(this).uniqueId().attr('id')] = false;
});
function resetRadioState() {
$("input[type='radio']").each(function() {
radios[$(this).attr('id')] = $(this).is(':checked');
});
}
resetRadioState();
$("input[type='radio']").click(function(e) {
alert(radios[$(this).attr('id')]);
resetRadioState();
});
})
</script>
<input type="radio" name="group[]"/>
<input type="radio" name="group[]" checked/>

onchange not working with radio button

I have a few radio buttons which should call hider(something); when they change, meaning when they are checked or unchecked. This works, i.e. when checked they call the JS function, however, if they're unchecked due to selecting another radio button from that group, it does not call the js script again.
Do I need to use something else than onchange?
This is what the radio buttons look like at the moment:
<input name="ostype" type="radio" value="0" onchange="hider(solaris);">solaris
<input name="ostype" type="radio" value="1" onchange="hider(linux);">linux
My hider function is currently:
function hider(divid) {
if ($(divid).is('.hidden')) {
$(divid).removeClass('hidden');
} else {
$(divid).addClass('hidden');
}
}
Since this question is still not answered correctly yet ranks quite high for me in Google for "radio button onchange", here's a proper solution for anyone still looking.
If you're using jQuery, just use jQuery's attribute selector as noted by Flavius Stef.
OP, it's not entirely clear what your code does. Let's assume in your code you want to add the "hidden" class to whatever radio button is active.
$("your selector here").change(function() {
$('input[name="' + this.name + '"]').removeClass("hidden");
$(this).addClass("hidden");
});
Please note the difference between $(this) (the jQuery object) and this (the DOM object). Basically I'm removing the "hidden" class from every input that goes by the same name, and then I add the "hidden" class to the current input.
Of course I'm assuming here that you're not using duplicate names for different inputs on the page. Also note that this would only work for radio buttons, as the radio button "change" event only fires when activated, not when deactivated.
Listening for onchange on both checkboxes and radio buttons
In my case, I wanted to add a "checked" class to active radio buttons and checkboxes. Since the checkbox fires the "onchange" event both when checked and unchecked, I needed a bit of extra code.
$('input[type="radio"]').change(function() {
$('input[name="' + this.name + '"]').removeClass("checked");
$(this).addClass("checked");
});
$('input[type="checkbox"]').change(function() {
$(this).toggleClass("checked", ($(this).is(":checked")));
});
The latter function uses toggleClass to set the "checked" class if .is(":checked") is true.
Alternatively you might want to combine the two functions into something like:
$('input[type="radio"], input[type="checkbox"]').change(function() {
if(this.type == "radio")
$('input[name="' + this.name + '"]').removeClass("checked");
$(this).toggleClass("checked", ($(this).is(":checked")));
});
Either way, always be careful when listening for an onclick event as it will not fire when the input is activated through keyboard navigation.
Use onclick.
Also as the argument of your function call you'll need to either use a string with the id as a jQuery selector ('#solaris') - better yet use this:
<input name="ostype" type="radio" value="0" onclick="hider(this);">solaris
Bind change event to ALL radio buttons on document ready:
$(function(){
$('input[name=list_type]:radio').on("change", function(){
showHideBlock();
});
showHideBlock();
});
Show -- hide block depends on ONE radio button status:
function showHideBlock(){
if ($("#Option").is(':checked')){
$('#Block').show();
} else {
$('#Block').hide();
}
}
<input name="ostype" type="radio" value="0" onclick="hider('solaris');">solaris
<input name="ostype" type="radio" value="1" onclick="hider('linux');">linux
function hider(divid) {
$( 'div.div_class' ).hide();
$( '#' + divid ).show();
}
Make sure you add a class to call the divs and make sure you put quotes around solaris and linux in the function calls
Here's a version that you might draw inspiration from (tested on Chrome and FF):
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">
</script>
</head>
<body>
<input type="radio" name="ostype" checked="checked" onclick="hider('linux')">linux
<input type="radio" name="ostype" onclick="hider('solaris');">solaris
<div id="content">
<div id="linux">linux</div>
<div id="solaris" style="display:none;">solaris</div>
</div>
<script>
function hider(divname) {
$('#content div').each(function(){
$(this).hide();
});
$('#'+divname).show();
}
</script>
</body>
</html>
If I understand you correctly you can just use an onClick on every button and hide the others while showing the one your clicking on.
Like this:
function showInfo(info)
{
var info = document.getElementById("1");
info.style.display = "block";
var info = document.getElementById("2");
info.style.display = "none";
}
So the first one is showing and the second one is hiding.
Then just add one for every div that should be hidden.
You can also do this with jQuery.
function showAndHide(val1, val2)
{
$(val1).hide();
$(val2).show();
}
And don't forget to have style="display:none" in every div.
did you declare the vars solaris and linux?
otherwise your browser should show you an Error

Checkbox onchange function

I have a page with a set of checkbox's, that I want to run a Javascript function on when there is a change (I have done something very similar with dropdown's - and that worked)
However with the checkbox's I have three problems:
my onChange event only runs "sometimes" (you have to change the focus between the different checkbox controls
when it does run it is returning the result of the previous checkbox (not the one just clicked on)
the jQuery always return the value true
Checkbox creation
<%= Html.CheckBox("sl-" + row.Id, value, new { onChange = "SuitabilityChecked("+row.Id+", "+key+")"})%>
Javascript
function SuitabilityChecked(providerId, parentRecordId) {
var params = {};
params.providerId = providerId;
params.parentRecordId = parentRecordId;
var value = $("#sl-" + providerId).val();
params.value = value;
$.getJSON("SuitabilityChecked", params, null);
};
Browsers are funny about radio buttons and check boxes and can delay the onchange until focus change. Try adding an onclick event to blur or call the change event directly.
Maybe something like this using jQuery Live (untested, off the top of my head):
$(':checkbox').live('click', function() { $(this).change(); });
What's happening:
Checkbox A clicked
Checkbox B clicked
Checkbox A has lost focus and fires onChange
Which makes it seem as if Checkbox B is returning the result of Checkbox A. If you were to press Tab after clicking Checkbox B in this scenario, you'd notice that its onChange would fire.

Categories

Resources