i'm trying to catch a change() on a select which is added after the dom generation but i can't success. Here is a sample code:
HTML:
<div class="test" id="divTest"></div>
jQuery:
$('#divTest').click(function(){ $(this).parent().append("<select id='testSel'><option value='f'>F</option><option value='F'>D</option></select>");});
$('#testSel').change(function(){
alert('change');
});
I want to see the alert when i change the value in the select..
And here is a fiddle.
http://jsfiddle.net/T8J8p/3/
Two problems:
Your select element's ID is #testS not #testSel.1
You need to use event delegation for this, through jQuery's on() method:
$('body').on('change', '#testS', function(){
alert('change');
});
JSFiddle demo.
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
1. This related to original JSFiddle featured in the question (available here). The question has since been edited.
You need event delegation dynamically added DOM::
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
$(document).on('change','#testS',function(){
alert('change');
});
Demo
Try this,
$('body').on("change", "#testSel", function(){
alert('change');
})
You have to bind event using event delegation as the element is added to the DOM after the DOM loaded:
$(document).on('change','#testSel',function(){
alert('change');
});
See Details HERE
$('#divTest').click(function(){
$(this).parent().append("<select id='testS'><option value='f'>F</option><option value='F'>D</option></select>");
$('#testS').change(function(){alert('change');});
});
You can't bid to something that does not exist yet, so bind it after the click, inside the function.
And there was a typo in the selector #testS vs #testSel
Related
I've attached delegated event handlers to a number of elements on the page using a single selector. As the events are triggered for individual elements, I'd like to turn off only that element's event handler based on some conditional logic. That means I won't necessarily want to disable the event on the very first click. But I can't figure out how to do it without turning off all of them.
HTML:
<button>One</button>
<button>Two</button>
<button>Three</button>
JS:
$(document).on('click', 'button', function(ev) {
// doesn't work because argument needs to be a string
$(document).off('click', $(ev.target));
// doesn't do what I want b/c turns off events on all buttons, not just this one
$(document).off('click', 'button');
// doesn't work because event is on document, not button
$(ev.target).off('click');
});
jQuery's off documentation says I need to provide a string as the second argument, not a jQuery object ($(ev.target)), but if I provide a string, there's no value that refers only to the item clicked.
From jQuery's off documentation:
To remove specific delegated event handlers, provide a selector
argument. The selector string must exactly match the one passed to
.on() when the event handler was attached. To remove all delegated
events from an element without removing non-delegated events, use the
special value "**".
So how do I turn off a delegated event handler for a specific element?
Here's a JSFiddle of the code above
UPDATE: Added a few examples of options that don't work, based on initial answers provided.
After having read thru on the web, the answer is you can't! You can either remove all or none. A workaround could be something like the following.
$(document).on('click', '.btn', function (ev) {
alert('pressed');
$(this).removeClass("btn");
});
Demo#Fiddle
Sample HTML:
<button class="btn">One</button>
<button class="btn">Two</button>
<button class="btn">Three</button>
In addition to what lshettyl said (the current top post) - an additional work around is to bind a new event listener directly to the element that you're trying to remove the listener and call stopPropagation() therein.
What this will do is prevent the event from traveling up the DOM and reaching the event handler that is initially bound to the document. Also this will allow you to keep some functionality on the button click, such as an alert to the user that this button has already been clicked - or something to that effect.
$(document).on('click', 'button', function(ev) {
// Your logic to occur on button click
// Prevent further click on just this button
$(this).click(function(event) {
event.stopPropagation();
}):
});
Question: Do you have to use the delegated events? LIke LShetty said, it is not possible to remove a delegated event for a single element. You either remove the entire event delegation, or leave it. You could try using a different selector instead like in this example
$('button').on('click', function(ev) {
$('#output').append('Clicked! ');
$(this).off('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<button>One</button>
<button>Two</button>
<button>Three</button>
<div id="output"></div>
click not working after i clear and append the html inside a div using jquery.
Here is the html code
<div id="divMain">
</div>
<input id="btn" type="button" value="Clear&Add"/>
Here is the jQuery code
var a = $('<a/>').attr({'id':'aH','href':'#'}).text('Hello');
a.click(function(){
alert('hello');
});
$('#divMain').append(a);
$('#btn').click(function(){
var newA = $('#aH');
$('#divMain').html('');
$('#divMain').append(newA);
});
Here is jsfiddle
Simple click on the alert link in fiddle , it shows an alert.Now click on the Clear&Add button .And now click on alert.It doesn't work.
You need event delegation to bind the event with dynamically added elements. You also need to create elemet with id aH as you have removed the element from DOM without preserving it.
Live Demo
$(document).on('click', '#aH', function(){
alert('hello');
});
You can try adding the globally created a and you would not need to bind click again.
$('#divMain').append(a);
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time. By
picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers, jQuery api
You need to use event delegation:
$('#divMain').on('click', a, function(){
alert('hello');
});
Updated Fiddle: http://jsfiddle.net/W95wV/1/
Click does not work on dynamically created elements in jQuery. In the earlier version of jQuery we could use .live('click') that has been deprecated in the recent versions. Now you can use .on to work better for dynamic elements as Adil said.
http://jsfiddle.net/q98G6/
HTML
<p>[QUESTION]</p>
<div class="answer-notdone">
<p>[CONTENT_1]</p>
</div
<div class="answer-notdone">
<p>[CONTENT_2]</p>
</div
<div class="answer-notdone">
<p>[CONTENT_3]</p>
</div
JavaScript
$(".answer-notdone").click(function(){
markQuestion(this); //external function
$(".answer-notdone").addClass('answer-complete').removeClass('answer-notdone');
)};
The example above is for a multiple choice question in a quiz - the user should only be able to click the answer once, and then it should be 'unlinked' from that jQuery function.
But the problem is even after the class has been removed successfully, the jQuery function is still called when clicked. Why?
Here is a fiddle I made of a demo, if the code above was not clear: http://jsfiddle.net/q98G6/
The selector is only used to find the elements, once the element is found and the event handler is attached to it, the selector does not have any relevance because the handlers are attached to the element not to the selector.
One way to solve the problem is to make use event delegation. In event delegation the handlers are attached to an ancestor element and we pass a selector as a target element. In this method the target selector is evaluated lazily.
$(document).on('click', ".answer-notdone", function(){
markQuestion(this); //external function
$(".answer-notdone").addClass('answer-complete').removeClass('answer-notdone');
)};
The selector returns all the elements that match it at the time you bind the handler, and then it attaches the handler to all those elements. Changing an element's class later does not remove the event handlers that were already bound.
If you want your handler to be bound to dynamically changing elements, you should use delegation:
$(document).on('click', '.answer-notdone', function() {
...
});
Try this
$(document).on('click',".answer-notdone",function () {
//markQuestion(this);
$(".answer-notdone").addClass('answer-complete').removeClass('answer-notdone');
});
FIDDLE DEMO
I want a new text input box will be appended when i click onto the latest generated text box.
But It generates new text input box only when i click the first text input box. So, any solution?
<script type="text/javascript">
$(function(event){
$('.add-new').click(function(){
$('.add-new').removeClass();
$('form').append("<br><input type='text' name='user[]' class='add-new'/>");
});
});
</script>
<div>
<form method='post' name='login'>
<input type='text' name='user[]' class='add-new'/>
</form>
</div>
$('form').on('click','.add-new', function(){
Direct event => Delegate Event
Live DEMO
Full code:
$('form').on('click', '.add-new', function() {
$(this).removeClass('add-new');
$(this).closest('form').append("<br><input type='text' name='user[]' class='add-new'/>");
});
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers.
on docs
demo http://jsfiddle.net/JuvwB/8/
Plz note: you should use $(this) as your even is bind to .add-new already.
rest all the above are nice solutions,
Hope this helps, cheers
code
$(function(event){
$('.add-new').on('click', function(){
$(this).removeClass();
$('form').append("<br><input type='text' name='user[]' class='add-new'/>");
});
});
$('form[name=login]').on('click', '.add-new', function() {
$(this).removeClass(); // $(this) instead of $('.add-new')
// $(this) point to the clicked element
// which you want
$('form').append("<br><input type='text' name='user[]' class='add-new'/>");
});
As you're changing the class name add-new and append new element dynamically with same class, so you need delegate event.
Read more about .on()
Note
syntax of .on() for delegate event
$(container).on(eventName, target, handlerFunction)
The reason why this doesn't work is because when you set the 'click' event your target doesn't exist, so no 'click' event is bound to it.
jQuery has a fancy function called the 'on' function that catches bubbling events.
$(document).on('click','.add-new', function(){
}
All events (click, mouseover, etc) start in the deepest node and bubble up through the html tree until the document. It is safe for you to catch them in the document, unless you explicitly call "stopPropagation" or return false on a processed in the middle of the bubling click handler function.
You can also catch it in the middle of the tree with $("form").on... or even $("div").on...
Please, consider this code:
<script>
$(function(){
$('#clickme').click(function(){
$('#note_pag').html('<div id="note_pag"><ul><li><b>1</b></li><li>2</li></ul></div>');
});
$('#note_pag a').click(function(){
alert($(this).attr('href'));
return false;
});
});
</script>
CLICK ME
<div id="note_pag">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
Could someone tell me why I can get the clicks on the links inside #node_app, but when I replace the div with .html() the event is not fired anymore?
Because your essentially using .bind (via .click) the events are only set for the current elements. You're then removing those elements. If you want those events to persist after you've altered the dom, use .live instead:
$("#note_page a").live("click", function() {
alert($(this).attr("href"));
return false;
});
You need live -
$('#note_pag a').live('click',function(){
alert($(this).attr('href'));
return false;
});
also, you should avoid creating a duplicate id when inserting the new content. You could chnage note_page to a class instead of an id.
$('#note_pag a')
This says "find all a elements within #note_pag". You then bind an event handler to those elements.
$('#note_pag').html('<div id="note_pag"><ul><li><b>1</b></li><li>2</li></ul></div>');
When you do this, the elements that the event handlers were bound to above are replaced. (Actually, you're also adding <div id="note_pag"> every time: you don't need to include the html of the element you're filling.)
Effectively, you need to bind the event handler to a different element, one that always exists. This is possible because ancestor elements are notified of events on descendant elements. The nicest way to do this with jQuery is the delegate method:
$('#note_pag').delegate('a', 'click', function() {
alert($(this).attr('href'));
return false;
});
Note that this does the same thing as live, but is significantly better optimised in various ways.
Binding to events via click() or bind() only works for objects that are already present in the DOM at the time of binding your event handler.
What you are looking for is jQuery's live() function, which allows you to bind handlers to not-yet-existing elements.
Your code would look like this:
$('#note_pag a').live('click', function(){
alert($(this).attr('href'));
return false;
});
Edit: To be precise, live() binds to $(document) and checks the target attribute of events that have bubbled all the way up through the DOM – that's why the binding works even though elements are added after binding the event callback.
Example HTML:
<div id="some_triggers">
<a id="foo" href="#">Foo!</a>
</div>
Example jQuery:
$('#foo').click(function(){ alert('foo') });
$('#bar').click(function(){ alert('bar') });
$('#some_triggers').append('<a id="bar" href="#">Bar!</a>');
$('#foo').live('click', function(){ alert('foo live()!') });
$('#bar').live('click', function(){ alert('bar live()!') });
// -> clicking #foo alerts "foo" and "foo live()"
// -> clicking #bar alerts "bar live()" only, since the '.click()' binding doesn't work on non-existent DOM elements.
Edit2:
As mentioned by some of the others (#Marnix, most notably), your "replacement" code is nesting elements with the same ID inside each other every time the click handler executes.
You should replace your
$('#note_pag').html('<div id="note_pag"><ul><li><b>1</b></li><li>2</li></ul></div>');
line with either
$('#note_pag').replaceWith('<div id="note_pag"><ul><li><b>1</b></li><li>2</li></ul></div>');
or
$('#note_pag').html('<ul><li><b>1</b></li><li>2</li></ul>');
event isn't set to the new html after the click
try:
$('#note_pag a').live('click', function(){
Instead of $('#note_pag a').click you would need to use $('#note_pag a').live("click",handler).
Reason : The event was attached to the a node and when you overrite the HTML it becomes a new a node
Try to use the .live()