jQuery: Any way to "refresh" event handlers? - javascript

I have two divs, one that holds some stuff and the other with all possible stuff. Clicking on one of the divs will transfer items to the other div. The code I came up with is:
$("#holder > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#bucket").append(this);
});
});
$("#bucket > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#holder").append(this);
});
});
This one works perfectly, except that the event handlers need to be refreshed once I append or remove elements. What I mean is, if I first click on an element, it gets added to the other div, but if I click on this element again, nothing happens. I can do this manually but is there a better way to achieve this?

Try jquery live events .. the $.live(eventname, function) will bind to any current elements that match as well as elements added to the Dom in the future by javascript manipulation.
example:
$("#holder > *").live("click", function(e) {
$(this).remove();
$("#bucket").append(this);
});
$("#bucket > *").live("click", function(e) {
$(this).remove();
$("#holder").append(this);
});
Important:
Note that $.live has since been stripped from jQuery (1.9 onwards) and that you should instead use $.on.
I suggest that you refer to this answer for an updated example.

First, live is deprecated. Second, refreshing isn't what you want. You just need to attach the click handler to the right source, in this case: the document.
When you do
$(document).on('click', <id or class of element>, <function>);
the click handler is attached to the document. When the page is loaded, the click handler is attached to a specific instance of an element. When the page is reloaded, that specific instance is gone so the handler isn't going to register any clicks. But the page remains so attach the click handler to the document. Simple and easy.

Here you go, using the more intuitive delegate API:
var holder = $('#holder'),
bucket = $('#bucket');
holder.delegate('*', 'click', function(e) {
$(this).remove();
bucket.append(this);
});
bucket.delegate('*', 'click', function(e) {
$(this).remove();
holder.append(this);
});

EDIT: don't use live, it be deprecated!
Take advantage of the fact that events bubble. Using .on():
var = function( el1, el2 ) {
var things = $('#holder, #bucket');
things.each(function( index ) {
// for every click on or in this element
things.eq(index).on('click', '> *', function() {
// append will remove the element
// Number( !0 ) => 1, Number( !1 ) => 0
things.eq( Number(!index) ).append( this );
});
});
any click on any element (existing at the time of bind or not) will bubble up (assuming you haven't manually captured the event and stopped propagation). Thus, you can use that event delegation to bind only two events, one on each container. Every click that passed the selector test of the 2nd argument (in this case, > *, will remove that element and then append it to the alternate container as accesesed by things.eq( Number(!index) )

Have you looked at jQuery's live function?

The most Efficient way (dont load all event for all elements) it:
//NORMAL FUNCTION
function myfunction_click(){
//custom action
}
$('id_or_class_of_element').on('click', myfunction_click);
//LOAD OR REFRESH EVENT
$(document).on('click', 'id_or_class_of_element', myfunction_click);

Related

'.on' click not running function?

I have a function that when it runs new markup is generated on the fly...
$('.search input[type="image"]').on('click', function(){
// Open directions in a map
if($('#TXT_SAddr').val() === ''){
return false;
$('.directions .search').css('background' , '#ff0000');
} else {
var from = $('#TXT_SAddr').val();
var to = $('.postal-code').html();
var directions = 'http://maps.google.com/maps?saddr=' + from + '&daddr=' + to + '&output=embed';
var modal = '<div class="apply-modal modal"><a class="close-apply-now" style="margin-bottom: 20px;"><img src="http://site.co.uk/images/closeModal.png" alt="Close" style="border-width:0px;"></a><div class="holder"><iframe src="'+directions+'" style="border:none; width:100%; height:500px;" border="0"></iframe></div></div>';
$('body').prepend('<div class="modalOverlay"/>' + modal);
$('.modal').animate({
'opacity': 1,
'top': '100px'
}, 700, 'easeOutBack');
}
return false;
});
If you can see, the above generates a div with an anchor under the class name of 'close-apply-now'.
I now want to bind a function to this and I've tried using...
$('a.close-apply-now').on('click', function(){
alert('asdasd');
});
with no luck, can anybody see where I may be going wrong? Not even my alert is working.
Since the close-apply-now div is added dynamically, you need to use event delegation to register the event handler like:
// New way (jQuery 1.7+) - .on(events, selector, handler)
$('body').on('click', 'a.close-apply-now', function(event) {
event.preventDefault();
alert('asdasd');
});
This will attach your click event to any anchors with class close-apply-now within the body element.
The syntax for event delegation is slightly different.
The event need to be bind to an element which is already existing in the dom while the target element selector needs to be passed as the second argument
$(document).on('click', 'a.close-apply-now', function(){
alert('asdasd');
});
The close-apply-now div is added dynamically. You have to add the selector parameter, otherwise the event is directly bound (doesn't work for dynamically loaded content) instead of delegated. See http://api.jquery.com/on/#direct-and-delegated-events
Change your code to
$(document.body).on('click', '.update' ,function(){
The jQuery set receives the event then delegates it to elements matching the selector given as argument. This means that contrary to when using live, the jQuery set elements must exist when you execute the code.
Use jQuery's live() method. Description: Attach an event handler for all elements which match the current selector, now and in the future.
$("a.close-apply-now").live("click", function(){
alert('asdasd');
});
Try Both in Jsfiddle

DataTable can't get id element after page change

I am trying to make ajax call on focus for every text input, I can make is in first page( when document ready) but when I change page , javascript can't parse inputs because it wasn't created when document is ready. How can I fix it ?
jQuery(document).ready( function(){
jQuery('[id^=urun_sirasi-]').focus(function(){
event.preventDefault();
var urun_sirasi=jQuery(this).data('sira');
console.log(urun_sirasi);
jQuery('#urun_sirasi-'+urun_sirasi).bind('keyup',function(e)
{
console.log(jQuery("#urun_sirasi-"+urun_sirasi).val());
jQuery.ajax({
url:'../ajax.php',
data:'process=siralama&urun_id='+urun_sirasi+'&urun_sirasi='+jQuery.trim(jQuery("#urun_sirasi-"+urun_sirasi).val()),
success:function(e){
// e -> 1 ve ya0 geliyor.
console.log(e);
}
});
});
});
});
Thanks for your help.
This seems to a very common problem in the jQuery section. See the docs for .on() at http://api.jquery.com/on/, specifically the section about delegated events:
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time.
I use the following syntax in the doc ready that will create events for all future items with the "expand" class, should be able to be adjusted for you
$(document).on('click',"#myTable .expand", function(){
so yours should be something like this (maybe give your items a class rather than having an event to each element selector)
$(document).on('keyup',"#yourTable .urun_sirasi-key", function(){

jquery not function miss element

I use a tool-tip to display error message on the page, I need it to be closed when I click elsewhere within the view. I use the below codes to control this action:
$(':not(.qtip)').click(function(){
$('.qtip').hide();
});
The ".qtip" is used for marking the tool-tip area. The tool-tip itself creates a new one when it comes out, what happened here is when I click on the tool-tip, it disappears.
But when I use a smaller scale of the selector instead of the whole body, it works fine, which is a little weird, for example:
$("#id").not('.qtip').click(function (){
$('.qtip').hide();
});
It would be advisable to just target document for handling the click outside of your tooltip; the selector for :not(.qtip) potentially returns a very big result set.
$(document).on('click', function() {
$('.qtip').hide();
}
On the tooltip itself you would need to prevent the click event from bubbling to document level, if you're not doing so yet:
$('.qtip').on('click', false);
Use event bubbling to your advantage
$(document).on("mouseup", function (e) {
var target = e.target || e.srcElement;
var container = $(".qtip");
if (container.not(target) && container.has(target).length === 0)
{
container.hide();
}
});
I suggest you to do two things:
$(document).click(function() {
$('.qtip').hide();
});
$('.qtip').click(function(e){
e.stopPropagation();
});
click of document to hide the .qtip
stop the event bubbling on click of .qtip, here click won't traverse up to the parent.
Try
$(document).on("click", function(e) {
var qtip = $(e.target).closest('.qtip');
if(!qtip.length)
$('.qtip').hide();
});

Trapping all `a` clicks including ones added dynamcally

I know you can bind to click events with jQuery like so:
$('a').click(function(){});
But what about html elements that are added dynamically? Lets say I have a div with the following contents:
<div>
<a href='location.html'>location</a>
</div>
Now I call:
$('a').click(
function(){
console.log("going to " + $(this).attr('href'));
return true;
});
And that will work fine. But if somewhere along the line I call
$('div').("<a href='location2.html'>location2</a>");
without explicitly binding that event handler to that event then the event handler will pick up on it.
Is it possible to rebind when ever a new a element is added. Or even better, when ever the location.href property is changing so I can add a get parameter to it every time.
For example if I was binding to a click event on an a element the event handler would be:
function(){
var newid = parseInt(Obj.Request('pageid'), 10) + 1;
location.href = $(this).attr('href') + '?pageid=' + newid.toString();
return false;
}
Assuming the Obj.Request is a function that returns a get parameter. (I already have this in place).
Use it in this manner:
$(document).on( 'click', 'a', function() {
console.log("going to " + $(this).attr('href'));
return true;
});
Working on your fiddle link.
You want to use the function .on.
$('a').on('click', function() {
//works on non dynamic elements present at page load
});
$('#some_non_dynamic_parent_ID').on('click', 'a', function() {
//works on dynamic elements added later
});
You want to use .on(), but as a delegation method.
Bind it to the closest static parent - for this example I'll just use body.
$('body').on('click', 'a', function(e){
e.preventDefault();
});
This will wait until the event bubbles up to the body element and check what the original target of the event was - if it was an a element, it'll fire the handler.
You can use .on() or live() functions if you use jquery upper then 1.7 version. About the difference of these functions you can read in this article

Dynamically added javascript is not working, but static code works fine?

Here is what I'm doing... I have a textbox that users type something in and click an add icon. This fires some jquery code that adds the item they typed into a span within a "content" div. The generated code has a delete icon that appears on hover and when clicked it should make the span disappear. This works if the code is on the page already (before document load) but if it's dynamically created, it breaks the delete on click functionality.
Here is a JSfiddle so you can see it in action: http://jsfiddle.net/WF32y/
What can I do to fix this? I essentially want to do what happens on here (stackoverflow.com) when you enter tags to a new question.
Use event delegation for dynamically added elements by changing this:
$('a.delete').on('click', function(e) {
Into this:
$(document).on('click', 'a.delete', function(e) {
Fiddle
.on() Direct and delegated events reference
Also, concerning performance, you can attach the handler to a closer ancestor of the dynamically added elements than the document (e.g. a static wrapper element).
You can easily do it with delegate. In your case:
$('#container').delegate('a.delete','click', function(e) {
e.preventDefault();
taskID = $(this).closest('.task')[0].id;
$(this).closest('.task').fadeTo(300, 0, function() {
$(this).animate({
width: 0
}, 200, function() {
$(this).remove();
});
});
});
And by the way FYI:
// jQuery version 1.4.3+
$('#container').delegate('a.delete'...
// jQuery 1.7+
$('#container').on('click', 'a.delete', function(e) {
it is faster and more propery way than:
$(document).on('a.delete'...
or:
$('body').delegate('a.delete'...
or:
$(document).delegate('a.delete'...

Categories