JQuery on change event firing for the wrong element - javascript

I have two <select> elements: select.exerciseType and #moduleTopic, each with their own handler wrapped around the document. I believe it's important to know that select.exerciseType is dinamic and there can be multiple of those.
Their events are:
$(document).ready(function() {
$(document).on("change", $("select.exerciseType"), function(e) {
<!--Code not really important-->
}
$(document).on("change", $("#moduleTopic"), function(e) {
<!--Code not really important-->
}
}
My problem is, when I change the selected option in one of those selects, both those events are firing. Why is the selector in the on() function not working and how can I make it work?

Syntax for jQuery .on handler is .on( events [, selector ] [, data ], handler ) where second argument is string
In your case, as it is not string, it is omitted and the event is always triggered when it reaches the selected element!
$(document).ready(function() {
$(document).on("change", "select.exerciseType", function(e) {});
$(document).on("change", "#moduleTopic", function(e) {});
});

Can you use this code instead:
$("#moduleTopic").change(function() {
// code executes here
});
EDIT ---
You can use a classname and detect the <select> being changed by the use of $(this) inside your function.

You don't need document.ready and you also just specify the selector, not retrieve it. i.e.
// class example
$(document).on("change", "select.exerciseType", function(e) {
// Code not really important
});
// ID example
$(document).on("change", "#moduleTopic", function(e) {
// Code not really important
});

Related

How to prevent jQuery duplicate function being called

I have a jQuery on('click') function like this:
function enabled_click() {
$('.btn_enabled').on('click', function() {
alert('CLICKED');
});
}
and then I have another post function like this
$(document).on('click', '.btn_add_link', function(e) {
var url = 'www.xxx.my-function';
post_data(url, function(data) {
if (data.status == 'success') {
$('#my_wrapper').append(data.response);
enabled_click();
} else {
alert('error');
}
});
return false;
});
The post function will append another .btn_enabled button. If i did not call the enabled_click() function on the success post, then the newly added .btn_enabled would not be able to trigger the onclick function.
But if I call the enabled_click() function like i did above, the already existing .btn_enable will then call the onclick function twice and alert CLICKED twice. Is there any way to make it so it only alerts once?
Event delegation by binding to a common parent, as answered by #qs1210, is a possible solution, and a very efficient one (because there's only one common handler instead of one per element). But depending on the code, it may require more changes.
As a compatible "drop-in replacment" just unbind the event handler before binding again. To achieve this in an easy and stable way, you can use jQuery's "namespace" feature for event names (see .on(), "Event names and namespaces"):
function enabled_click(){
$( '.btn_enabled' )
.off('click.some_namespace')
.on('click.some_namespace'), function() {
alert('CLICKED');
});
}
Note: if you extract the event handler into its own function and use that as second parameter to .off(), you could omit the namespace:
function click_handler(){
alert('CLICKED');
}
function enabled_click(){
$( '.btn_enabled' )
.off('click', click_handler)
.on('click', click_handler);
}
But this only works it the click_handler variable is "stable": depending where and when the click handler is defined, the variable (click_handler in this example) could be re-assigned and .off() couldn't detach the previous handler anymore.
Follow-up: in your example, you only apply the event handler to newly appended elements ($('#my_wrapper').append(data.response)). You could alter enabled_click to explicitly take the new element(s) as an argument:
function enabled_click($element){
$element.find('.btn_enabled' ).on('click', function() {
alert('CLICKED');
});
}
and call it like this:
var $newElement = $(data.response);
$('#my_wrapper').append($newElement);
enabled_click($newElement);
Now the event handler gets attached to new elements only, and not to already existing which have the event handler already attached.
(I'm using $ as prefix for all my variables holding jQuery collections, in order to distinguish them from pure DOM nodes)
Your can write like this
document.on('click', '.btn_enabled', function() {
alert('CLICKED');
})`
delegate event to dom, it makes everything harmony.

listening event after id changing

I want to modify an Id of button 'B' when button 'A' is clicked, and listen to the click event of of 'B' using Jquery but my code doesn't work,
this is an example of my code:
$(function() {
$(".nuttonA").click(
function() {
$("#buttonB").attr("id","notButtonB");
});
$("#notButtonB").click(function(){
console.log(" notButtonB is clicked "); //show nothing
});
});
i think you need event delegation. try this:
$(function() {
$(".buttonA").click(
function() {
$("#buttonB").attr("id","notButtonB");
});
$( "body" ).on( "click", "#notButtonB",function(){
console.log(" notButtonB is clicked "); //show nothing
});
});
Currently what you are using is called a "direct" binding which will only attach to element that exist on the page at the time your code makes the event binding call.
You need to use Event Delegation using delegated-events approach when manipulation properties.
General Syntax
$(document).on('event','selector',callback_function)
Example
$(document).on('click', ".nuttonA", function(){
$("#buttonB").attr("id","notButtonB");
});
$(document).on('click', "#notButtonB", function(){
//Your code
});
In place of document you should use closest static container.

Passing a jQuery object in event delegation

// Snippet 1
$(document).on("keyup blur", "#selector_1_id", function() {
// DO SOMETHING
});
$(document).on("keyup blur", "#selector_2_id", function() {
// DO SOMETHING
});
// Snippet 2
var selector_1_id = $("input[name=selector_1_id]");
var selector_2_id = $("input[name=selector_2_id]");
$(document).on("keyup blur", selector_1_id, function() {
// DO SOMETHING
});
$(document).on("keyup blur", selector_2_id, function() {
// DO SOMETHING
});
Why do these snippets seem to be behaving differently? While the first one actually seems to work as ideal, that is keyup and blur being actually applied on the selector on keyup and blur event, while the other seems to be not working that ideally, it behaves like the snippet keeps on running always.
I am enabling and disabling input types on the live website using JavaScript.
You cannot pass a element through that function like that, it has to be the string selector.
$(document).on("keyup blur", selector_2_id, function() {
// DO SOMETHING
});
Won't work, in-fact the keyup and blur will be triggered every single time on the document rather than the selector
If you have the element in a variable there is no need to do this because you have a reference to the element anyway you only use this if the element can be added any time and you don't have a reference to it.
So
selector_2_id.on('keyup blur', function() {
// DO SOMETHING
});
Should work perfectly.
Deeper look
A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element.
So what this means is this
$(document).on('keyup blur', selector_2_id, function(){
^------^ = 1 ^-----------^ = 2
});
If 2 is null or omitted then 1 will be used for the event
As per the api , the selector need's to be a string and not a jquery object
selector Type: String - A selector string to filter the descendants of
the selected elements that trigger the event. If the selector is null
or omitted, the event is always triggered when it reaches the selected
element.
http://api.jquery.com/on/
I believe this is what you are trying to do:
// Snippet 2
var selector_1_id = "input[name=selector_1_id]";
var selector_2_id = "input[name=selector_2_id]";
$(document).on("keyup blur", selector_1_id, function() {
// DO SOMETHING
});
$(document).on("keyup blur", selector_2_id, function() {
// DO SOMETHING
});
The above will work (passing a string var as the selector), but why not just:
$(document).on("keyup blur", "input[name=selector_1_id]", function() {
// DO SOMETHING
});
$(document).on("keyup blur", "input[name=selector_2_id]", function() {
// DO SOMETHING
});
...unless you have a greater context in which you create this string or do something with it.

Single .on click for multiple elements

I have the following jquery...
$(".parentElem").on("click", "input[id*='myitem']", function() {
myfunction();
});
and
$(".parentElem").on("click", "input[id*='myotheritem']", function() {
myfunction();
});
These both work fine, but I don't want to have to list every clickable element separately... I'd much rather list them all at once - something like this...
$(".parentElem").on("click", "input[id*='myitem'], input[id*='myotheritem']", function() {
myfunction();
});
Is this possible? It doesn't seem to work for me.
The second argument in the .on() method is a CSS selector. So you don't have to pass in each individual element with their ID. You could just use a generic class or selector like this:
$('.parentElem').on('click', 'input', function(event) {
// Function body here
});
Simply don't use the delegation feature, instead do your own checking:
$(".parentElem").on("click", function() {
// check if event.target matches an element that you want to trigger on
});
This works for me:
$(".parentElem").find("input[id*='myitem'], input[id*='myotheritem']").each(function(){
$(this).click(function(){
myfunction();
});
});
DEMO

jQuery .on('change', function() {} not triggering for dynamically created inputs

The problem is that I have some dynamically created sets of input tags and I also have a function that is meant to trigger any time an input value is changed.
$('input').on('change', function() {
// Does some stuff and logs the event to the console
});
However the .on('change') is not triggering for any dynamically created inputs, only for items that were present when the page was loaded. Unfortunately this leaves me in a bit of a bind as .on is meant to be the replacement for .live() and .delegate() all of which are wrappers for .bind() :/
Has anyone else had this problem or know of a solution?
You should provide a selector to the on function:
$(document).on('change', 'input', function() {
// Does some stuff and logs the event to the console
});
In that case, it will work as you expected. Also, it is better to specify some element instead of document.
Read this article for better understanding: http://elijahmanor.com/differences-between-jquery-bind-vs-live-vs-delegate-vs-on/
You can use any one of several approaches:
$("#Input_Id").change(function(){ // 1st way
// do your code here
// Use this when your element is already rendered
});
$("#Input_Id").on('change', function(){ // 2nd way
// do your code here
// This will specifically call onChange of your element
});
$("body").on('change', '#Input_Id', function(){ // 3rd way
// do your code here
// It will filter the element "Input_Id" from the "body" and apply "onChange effect" on it
});
Use this
$('body').on('change', '#id', function() {
// Action goes here.
});
Just to clarify some potential confusion.
This only works when an element is present on DOM load:
$("#target").change(function(){
//does some stuff;
});
When an element is dynamically loaded in later you can use:
$(".parent-element").on('change', '#target', function(){
//does some stuff;
});
$("#id").change(function(){
//does some stuff;
});
you can use:
$('body').ready(function(){
$(document).on('change', '#elemID', function(){
// do something
});
});
It works with me.
You can use 'input' event, that occurs when an element gets user input.
$(document).on('input', '#input_id', function() {
// this will fire all possible change actions
});
documentation from w3
$(document).on('change', '#id', aFunc);
function aFunc() {
// code here...
}

Categories

Resources