Add event handler to an element that not yet exists using on()? - javascript

I want to add an event handle to an element that will be created later in DOM.
Basically, what I am trying to do is that, when I click p#one, new element p#two will be created, then I click p#two, tell me "p#two" clicked. However, it doesn't work, I didn't get the console.log result of 'p#two clicked' after I click p#two.
I use on() to add click event to p#two. What do I do wrong?
Thanks.
Below is my example code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>on() test</title>
<link type="text/css" href="http://localhost/jquery-ui-1.8.20.custom/css/smoothness/jquery-ui-1.8.20.custom.css" rel="stylesheet" />
<script type="text/javascript" src="http://localhost/jquery-ui-1.8.20.custom/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://localhost/jquery-ui-1.8.20.custom/js/jquery-ui-1.8.20.custom.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('p#two').on('click', function() {
console.log('p#two clicked');
});
$('p#one').click(function() {
console.log('p#one clicked');
$('<p id="two">two</p>').insertAfter('p#one');
});
}); // end doc ready
</script>
</head>
<body>
<p id="one">one</p>
</body>
</html>

$('body').on('click','p#two', function() {
console.log('p#two clicked');
});
you can also use
$(document).on('click', 'p#two', function() {
});
Read more about .on()
you can also use .delegate()
$('body').delegate('#two', 'click', function() {
});

You can bind the $.on to a parent element that will always exist in dom like this.
$(document).on('click','p#two', function() {
console.log('p#two clicked');
});
Note that: you can replace document with any parent of the element that will always exist in dom, and the closer the parent the better.
Check doc of $.on
Live is depreciated. use $.on instead. Equivalent syntax of $.on for $.live and $.delegate
$(selector).live(events, data, handler); // jQuery 1.3+
$(document).delegate(selector, events, data, handler); // jQuery 1.4.3+
$(document).on(events, selector, data, handler); // jQuery 1.7+
I would suggest you to use $.on for all event handling purposes as all other methods routes through $.on method under the hood.
Check the definition of these functions from jQuery source v.1.7.2
bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},
live: function( types, data, fn ) {
jQuery( this.context ).on( types, this.selector, data, fn );
return this;
},
die: function( types, fn ) {
jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
},
delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
// ( namespace ) or ( selector, types [, fn] )
return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
}
You can see all methods are using $.on and $.off themselves. So using $.on you can at least save a function call though which isn't that significant most of the cases.

You want to use Jquery.on
$('body').on('click','p#two', function() {
console.log('p#two clicked');
});

Related

What is javascript version of jquery's on() &trigger() (with ability to catch parameters)

I have checked all stackoverflow about javascript version version of jquery's on(). But none of them have the ability to catch parameters like real jquery's on().
In official jquery docs about .on() they support .on( events [, selector ] [, data ], handler )
But all javascript equivalent version i found only can do like this .on( events [, selector ], handler ). negleting the data attribute.
I have also checked all stackoverflow about javascript version version of jquery's trigger(). But none of them have the ability to pass parameters like real jquery's trigger().
In official jquery docs about .trigger() they support .trigger( event [, extraParameters ] )
But all javascript equivalent version i found only can do like this .trigger( event ). negleting the extraParameters attribute.
Please do not referencing the current js equivalent of .on & .trigger that you an find online. I have searched it for 3days. None of them can pass/receive parameters like jquery do.
So, what is vanilla javascript version jquery's trigger() & on() but with ability to pass and receive parameters. for example like this code:
$( "#foo" ).on( "click", function( event, parameters ) {
alert( parameters.param1 );
});
$( "#foo").trigger( "click", [ { 'param1': true } ] );
You can trigger a custom event with data using the following function:
// See: http://youmightnotneedjquery.com
const triggerEvent = (el, eventName, data) => {
let event;
if (window.CustomEvent && typeof window.CustomEvent === 'function') {
event = new CustomEvent(eventName, { detail: data });
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(eventName, true, true, data);
}
el.dispatchEvent(event);
};
const
fooEl = document.querySelector('#foo'),
onClick = e => console.log(e.target, e.detail.param1);
fooEl.addEventListener('click', onClick);
triggerEvent(fooEl, 'click', { param1: true });
<button id="foo">Foo</button>
<!--
$("#foo").on("click", function(event, parameters) {
alert(parameters.param1);
});
$("#foo").trigger("click", [{
'param1': true
}]);
-->
Pass a function into addEventListener that takes the event parameter and passes on that parameter and whatever else you want to pass:
const doSomething = (event, otherArg) => {
console.log('Target:', event.target);
console.log('otherArg:', otherArg);
};
document.querySelector('button').addEventListener('click', e => doSomething(e, 'foobar'));
<button>click</button>

Check for changes to class attribute on click [duplicate]

I would like to have something like:
$('#myDiv').bind('class "submission ok" added'){
alert('class "submission ok" has been added');
});
There is no event raised when a class changes. The alternative is to manually raise an event when you programatically change the class:
$someElement.on('event', function() {
$('#myDiv').addClass('submission-ok').trigger('classChange');
});
// in another js file, far, far away
$('#myDiv').on('classChange', function() {
// do stuff
});
UPDATE - 2015
This question seems to be gathering some visitors, so here is an update with an approach which can be used without having to modify existing code using the new MutationObserver:
var $div = $("#foo");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var attributeValue = $(mutation.target).prop(mutation.attributeName);
console.log("Class attribute changed to:", attributeValue);
});
});
observer.observe($div[0], {
attributes: true,
attributeFilter: ['class']
});
$div.addClass('red');
.red {
color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo" class="bar">#foo.bar</div>
Be aware that the MutationObserver is only available for newer browsers, specifically Chrome 26, FF 14, IE 11, Opera 15 and Safari 6. See MDN for more details. If you need to support legacy browsers then you will need to use the method I outlined in my first example.
UPDATE - 2022
Here's an implementation of the above wrapped in to a jQuery extension method:
// extension method:
$.fn.classChange = function(cb) {
return $(this).each((_, el) => {
new MutationObserver(mutations => {
mutations.forEach(mutation => cb && cb(mutation.target, $(mutation.target).prop(mutation.attributeName)));
}).observe(el, {
attributes: true,
attributeFilter: ['class'] // only listen for class attribute changes
});
});
}
// usage:
const $foo = $("#foo").classChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));
const $fizz = $("#fizz").classChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));
// trigger
$('#trigger').on('click', () => {
$foo.removeClass('red');
$fizz.addClass('green dark-bg');
});
.red {
color: #C00;
}
.green {
color: #0C0;
}
.dark-bg {
background-color: #666;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<button id="trigger">Change classes</button>
<div id="foo" class="bar red">#foo.bar</div>
<div id="fizz" class="buzz">#fizz.buzz</div>
You could replace the original jQuery addClass and removeClass functions with your own that would call the original functions and then trigger a custom event. (Using a self-invoking anonymous function to contain the original function reference)
(function( func ) {
$.fn.addClass = function() { // replace the existing function on $.fn
func.apply( this, arguments ); // invoke the original function
this.trigger('classChanged'); // trigger the custom event
return this; // retain jQuery chainability
}
})($.fn.addClass); // pass the original function as an argument
(function( func ) {
$.fn.removeClass = function() {
func.apply( this, arguments );
this.trigger('classChanged');
return this;
}
})($.fn.removeClass);
Then the rest of your code would be as simple as you'd expect.
$(selector).on('classChanged', function(){ /*...*/ });
Update:
JS Fiddle Demo
This approach does make the assumption that the classes will only be changed via the jQuery addClass and removeClass methods. If classes are modified in other ways (such as direct manipulation of the class attribute through the DOM element) use of something like MutationObservers as explained in the accepted answer here would be necessary.
Also as a couple improvements to these methods:
Trigger an event for each class being added (classAdded) or removed (classRemoved) with the specific class passed as an argument to the callback function and only triggered if the particular class was actually added (not present previously) or removed (was present previously)
Only trigger classChanged if any classes are actually changed
(function( func ) {
$.fn.addClass = function(n) { // replace the existing function on $.fn
this.each(function(i) { // for each element in the collection
var $this = $(this); // 'this' is DOM element in this context
var prevClasses = this.getAttribute('class'); // note its original classes
var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString(); // retain function-type argument support
$.each(classNames.split(/\s+/), function(index, className) { // allow for multiple classes being added
if( !$this.hasClass(className) ) { // only when the class is not already present
func.call( $this, className ); // invoke the original function to add the class
$this.trigger('classAdded', className); // trigger a classAdded event
}
});
if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged'); // trigger the classChanged event
});
return this; // retain jQuery chainability
}
})($.fn.addClass); // pass the original function as an argument
(function( func ) {
$.fn.removeClass = function(n) {
this.each(function(i) {
var $this = $(this);
var prevClasses = this.getAttribute('class');
var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString();
$.each(classNames.split(/\s+/), function(index, className) {
if( $this.hasClass(className) ) {
func.call( $this, className );
$this.trigger('classRemoved', className);
}
});
if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged');
});
return this;
}
})($.fn.removeClass);
With these replacement functions you can then handle any class changed via classChanged or specific classes being added or removed by checking the argument to the callback function:
$(document).on('classAdded', '#myElement', function(event, className) {
if(className == "something") { /* do something */ }
});
Use trigger to fire your own event. When ever you change class add trigger with name
JS Fiddle DEMO
$("#main").on('click', function () {
$("#chld").addClass("bgcolorRed").trigger("cssFontSet");
});
$('#chld').on('cssFontSet', function () {
alert("Red bg set ");
});
you can use something like this:
$(this).addClass('someClass');
$(Selector).trigger('ClassChanged')
$(otherSelector).bind('ClassChanged', data, function(){//stuff });
but otherwise, no, there's no predefined function to fire an event when a class changes.
Read more about triggers here

How to fire an event on class change using jQuery?

I would like to have something like:
$('#myDiv').bind('class "submission ok" added'){
alert('class "submission ok" has been added');
});
There is no event raised when a class changes. The alternative is to manually raise an event when you programatically change the class:
$someElement.on('event', function() {
$('#myDiv').addClass('submission-ok').trigger('classChange');
});
// in another js file, far, far away
$('#myDiv').on('classChange', function() {
// do stuff
});
UPDATE - 2015
This question seems to be gathering some visitors, so here is an update with an approach which can be used without having to modify existing code using the new MutationObserver:
var $div = $("#foo");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
var attributeValue = $(mutation.target).prop(mutation.attributeName);
console.log("Class attribute changed to:", attributeValue);
});
});
observer.observe($div[0], {
attributes: true,
attributeFilter: ['class']
});
$div.addClass('red');
.red {
color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo" class="bar">#foo.bar</div>
Be aware that the MutationObserver is only available for newer browsers, specifically Chrome 26, FF 14, IE 11, Opera 15 and Safari 6. See MDN for more details. If you need to support legacy browsers then you will need to use the method I outlined in my first example.
UPDATE - 2022
Here's an implementation of the above wrapped in to a jQuery extension method:
// extension method:
$.fn.classChange = function(cb) {
return $(this).each((_, el) => {
new MutationObserver(mutations => {
mutations.forEach(mutation => cb && cb(mutation.target, $(mutation.target).prop(mutation.attributeName)));
}).observe(el, {
attributes: true,
attributeFilter: ['class'] // only listen for class attribute changes
});
});
}
// usage:
const $foo = $("#foo").classChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));
const $fizz = $("#fizz").classChange((el, newClass) => console.log(`#${el.id} had its class updated to: ${newClass}`));
// trigger
$('#trigger').on('click', () => {
$foo.removeClass('red');
$fizz.addClass('green dark-bg');
});
.red {
color: #C00;
}
.green {
color: #0C0;
}
.dark-bg {
background-color: #666;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<button id="trigger">Change classes</button>
<div id="foo" class="bar red">#foo.bar</div>
<div id="fizz" class="buzz">#fizz.buzz</div>
You could replace the original jQuery addClass and removeClass functions with your own that would call the original functions and then trigger a custom event. (Using a self-invoking anonymous function to contain the original function reference)
(function( func ) {
$.fn.addClass = function() { // replace the existing function on $.fn
func.apply( this, arguments ); // invoke the original function
this.trigger('classChanged'); // trigger the custom event
return this; // retain jQuery chainability
}
})($.fn.addClass); // pass the original function as an argument
(function( func ) {
$.fn.removeClass = function() {
func.apply( this, arguments );
this.trigger('classChanged');
return this;
}
})($.fn.removeClass);
Then the rest of your code would be as simple as you'd expect.
$(selector).on('classChanged', function(){ /*...*/ });
Update:
JS Fiddle Demo
This approach does make the assumption that the classes will only be changed via the jQuery addClass and removeClass methods. If classes are modified in other ways (such as direct manipulation of the class attribute through the DOM element) use of something like MutationObservers as explained in the accepted answer here would be necessary.
Also as a couple improvements to these methods:
Trigger an event for each class being added (classAdded) or removed (classRemoved) with the specific class passed as an argument to the callback function and only triggered if the particular class was actually added (not present previously) or removed (was present previously)
Only trigger classChanged if any classes are actually changed
(function( func ) {
$.fn.addClass = function(n) { // replace the existing function on $.fn
this.each(function(i) { // for each element in the collection
var $this = $(this); // 'this' is DOM element in this context
var prevClasses = this.getAttribute('class'); // note its original classes
var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString(); // retain function-type argument support
$.each(classNames.split(/\s+/), function(index, className) { // allow for multiple classes being added
if( !$this.hasClass(className) ) { // only when the class is not already present
func.call( $this, className ); // invoke the original function to add the class
$this.trigger('classAdded', className); // trigger a classAdded event
}
});
if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged'); // trigger the classChanged event
});
return this; // retain jQuery chainability
}
})($.fn.addClass); // pass the original function as an argument
(function( func ) {
$.fn.removeClass = function(n) {
this.each(function(i) {
var $this = $(this);
var prevClasses = this.getAttribute('class');
var classNames = $.isFunction(n) ? n(i, prevClasses) : n.toString();
$.each(classNames.split(/\s+/), function(index, className) {
if( $this.hasClass(className) ) {
func.call( $this, className );
$this.trigger('classRemoved', className);
}
});
if( prevClasses != this.getAttribute('class') ) $this.trigger('classChanged');
});
return this;
}
})($.fn.removeClass);
With these replacement functions you can then handle any class changed via classChanged or specific classes being added or removed by checking the argument to the callback function:
$(document).on('classAdded', '#myElement', function(event, className) {
if(className == "something") { /* do something */ }
});
Use trigger to fire your own event. When ever you change class add trigger with name
JS Fiddle DEMO
$("#main").on('click', function () {
$("#chld").addClass("bgcolorRed").trigger("cssFontSet");
});
$('#chld').on('cssFontSet', function () {
alert("Red bg set ");
});
you can use something like this:
$(this).addClass('someClass');
$(Selector).trigger('ClassChanged')
$(otherSelector).bind('ClassChanged', data, function(){//stuff });
but otherwise, no, there's no predefined function to fire an event when a class changes.
Read more about triggers here

Best jQuery plugin implementation for binding JavaScript's oninput event

I know jQuery doesn't support the oninput event, so have myself started to write a plugin to do the job. Although don't understanding very well all the stuff related to events in jQuery or JavaScript I ended up with usable code that currently satisfies my requirements.
Unfortunately I think my current implementation can crash, specially when using it in conjunction with other libraries because am setting directly the oninput member of the DOM elements.
Do you know a better and portable way to solve this problem, maybe using methods such as jQuery's "on" or JavaScript "addEventListener"?
Here is a working example of the code i'm currently using:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type="text/javascript">
////////////////////////////////////////////////////////////////////////////
// jQuery plugin to bind an event handler to the "oninput" JavaScript event.
(function ($) {
// Add an "input" method to all jQuery objects
$.fn.input = function (handler) {
// iterate over all DOM elements in the jQuery object
this.each( function () {
// set a new method to run when "oninput" is fired
this.oninput = function (prevHandler) {
return function (ev) {
// call previous handler if exists
if( typeof prevHandler === 'function' ) {
prevHandler.call (this, ev);
}
// call new handler
handler.call (this, ev);
};
}(this.oninput); // immediate evaluation, pass current handler as argument
});
};
} (jQuery));
////////////////////////////////////////////////////////////////////////////
</script>
<script type="text/javascript">
// Test the plugin
$(document).ready (function () {
$('#one').input (function () {
alert ('Input on one: ' + $(this).val());
});
$('#three,#four').input (function () {
alert ('Input on three or four: ' + $(this).val());
});
$('#one,#two,#three').input (function () {
alert ('Input on one, two, or three: ' + $(this).val());
});
$('#one,#two,#three,#four').input (function () {
alert ('Input on any: ' + $(this).val());
});
});
</script>
</head>
<body>
<input id='one'/><br/>
<input id='two'/><br/>
<input id='three'/><br/>
<input id='four'/><br/>
</body>
</html>
Thanks in advance!!
jQuery's 'on' can handle any event so you could simply do something like this:
(function() {
var outputElement = document.getElementById('mirror-input');
$('#input-stuff').on('input', function (event) {
outputElement.innerText = event.target.value;
});
}())
http://jsfiddle.net/YCAtZ/

javascript id select

I have a javascript function that someone made for me. I am kind of a noob at raw javascript. I use jquery quite often so I have been spoiled. Right now the function runs when someone clicks anywhere on the page because the document selector is used to trigger the function. I want the function to run when a specific id is clicked. I do have jquery installed as well. Anyone have any suggestions?
addEvent('#id', 'click', function(){ does not work
addEvent(document.getElementById("id"), 'click', function(){ does not work
function addEvent(obj, type, fn) {
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, false );
}
addEvent(document, 'click', function(){
seems to work:
http://fiddle.jshell.net/MT3ye/
The jquery way.
$("#objId").click(function(){ doSomething();});
Use document.getElementById('id') instead of document.
You should have a look at this:
https://developer.mozilla.org/en/The_DOM_and_JavaScript
how about using the
addEvent($('#id'), 'click', function(){
Would this work for you ...
$(document).ready(function ()
{
$("#element_id").click ( function(){ ... } );
...
}

Categories

Resources