Why OnChange Event is not Dispatched When Target Is Manually Set - javascript

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.

Related

Trigger checkbox change event with plain javascript (NOT jQuery)

I'm building a multiple select with ES6. It's all up and functional (moving trough items, clicking them, highlighting, whatever you want) but the only problem is handling those checkboxes. Whenever an item is highlighted and enter is pressed I must catch the event, verify the number of checked items and update dropdown's title.
The methods I found so far are based on using document.createEvent() and fireEvent(), but they both are deprecated (and yes, I can't figgure out how to solve it with CustomEvent).
I've been trying to find an answer for 3 days now, trust me when I say I tried my best.
checkbox.checked = true
checkbox.checked = false
only change checkbox value but won't trigger any event
Since changing a checkbox value doesn't trigger any event, of course it won't trigger neither 'click' nor 'change' event. They must be triggered separately or together on whatever the case, and the listeners must be specific as well, and new Event('change') works just fine. It was a matter of how to trigger and listen the events.
Thanks for the answers :-)
It might sound stupid, but have you tried simply calling click?
checkbox.click()
Not sure if applicable in OP's concrete case (that is not described in the question), but in general it should NOT be necessary to trigger events from inside your own code when it's possible to just call the same function from multiple places, e.g.:
const checkboxes = document.getElementsByTagName('input')
const button = document.getElementById('button')
const postProcess = (msg) => {console.log(`Processing after clicking ${msg}`)}
[...checkboxes].forEach(checkbox => {
checkbox.onclick = (e) => {
postProcess(`checkbox '${e.currentTarget.value}'`)
}
})
button.onclick = () => {
const previous = checkboxes[0].checked
checkboxes[0].checked = !previous
postProcess(`button that turned checkbox 'a' ${previous ? 'off' : 'on'}`)
}
<label><input type="checkbox" value="a">A</label>
<label><input type="checkbox" value="b">B</label>
<button id="button">Toggle A</button>

javascript getting a variable from a child to a parent

I shortened my code dramatically but below relays the point pretty efficiently, I'm trying to get the variable "Monitor" to update if the buttons pressed. I can get the variable through to my code if I put all of my code inside of the "button.onclick" function. However, my code won't run until I press the button. I need my code to run and if a button is pressed it updates my code.
<form name="form1">
<span id="buttons">
<input type="button" name="button1" value="funny1"/>
<input type="button" name="button2" value="funny2"/>
</span>
</form>
<script type="text/javascript">
var Monitor, buttonsDiv=document.getElementById("buttons");
Monitor = "funny1"
for (var i=1; i<=2; i++) {
var button = document.form1["button" + i];
button.onclick = function() {
buttons.Monitor = this.value;
};
/*lots of my own code that runs
inside of my for loop waiting
to reference monitor for an update*/
</script>
Hopefully the following code will get you going in the right direction. Instead of wiring up all the events per button, I think you were trying to get it so each button would then call into a function that would set the value of Monitor.
var Monitor = "funny1";
//selecting all elements named button
var buttons = document.querySelectorAll('input[type="button"]');
//For each of the buttons wire up an event listener
for(var i=0, length=buttons.length; i < length;i++)
{
//create a reference shorthand
var button = buttons[i];
//add the event listener for a click
button.addEventListener('click', function(event)
{
//on the event look at the event's target property to find the element that invoked the click
Monitor = event.target.value;
console.log(Monitor); //Output the value of monitor the the console
});
}
This code first finds all the inputs with type=button. I suggest you perhaps give the inputs a class instead to make the selector clearer, your choice. Secondly, I loop through the buttons and wire an event up for each one. The event then sets the value of the Monitor variable.
http://jsfiddle.net/wcf4c/

Radio button group - change events for buttons become deselected?

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.

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.

Input change event on blur

I need to trigger an input change event, but only if the value changed. And I need this done from a keyboard event. Is there a way to invoke the browser's change mechanism which will either trigger the change event to fire, or will not depending on if the value was modified?
Example:
User clicks on an input field
User does not modify value of the field
user presses a key causing the input field to blue
onchange does not get triggered.
vs
User clicks on an input field
User modifies the value of the field
user presses a key causing the input field to blue
onchange gets triggered.
Is this possible? Or I need to do the onfocus save value, onblur compare and possibly call onchange, but only if onchange was not already called because the user just navigated away by clicking vs say a keyboard trigger.
What key is it? If that key isn't a standard input key, set the onchange to check the field for the change of the field.
You also can bind an onkeypress do the document, and return:false; when the key that changes the input to blue is pressed.
A little more context could help.
If I get you right, you need two variables to remember previous and current states of the input, and a listener to handle interaction:
<html>
<head>
<script language="javascript">
var startFieldValue = "Some value, possibly value of input when it is loaded";
var endFieldValue = "";
var focusFlag = 0;
function interact(keyEvent) {
if(focusFlag == 1)
return true;
var key = keyEvent.keyCode? keyEvent.keyCode : keyEvent.charCode
if(String.fromCharCode(key) == "a") {
if(startFieldValue != endFieldValue) {
var elem = document.getElementById('input-to-be-changed');
elem.style.backgroundColor = "blue";
startFieldValue = endFieldValue;
}
}
}
</script>
</head>
<body onkeypress="interact(event);">
<input id="input-to-be-changed" onchange="endFieldValue = document.getElementById('input-to-be-changed').value;" onfocus="focusFlag = 1;" onblur="focusFlag = 0;">
</body>
Just read the comment on previous post, you should have global idea of what's going on, though. Changes are removing checking for focus, and placing listner (onkeypress) inside every input. The function interact should take 2 values - event and id of input to focus next. Also focusing new element should change startFieldValue.
Sorry to not write code itself, but it's kinda late and I really need some sleep.

Categories

Resources