Javascript, jQuery - how signed actions to just created object? - javascript

I am trying to make simple list with ability to add and delete elements. For now I am working on adding and performing a simple action on each of list elements object (existing and added). Unfortunately I have met some difficulties with that. I am able to modify objects that are created at the beginning, but not one added during "webpage working".
First of all my idea was to add AJAX to this, but I don't think it is the easiest way.
I think that some time ago (I don't remember where) I read how to make this work, but now I don't know. I would be really glad if someone would help me with this or at least give a link to good explanation of this.
There is what I have done so far (well this is mostly just a scratch, but the main idea is in it): http://jsfiddle.net/sebap123/pAZ7H/0
$("li").click(function() {
$(this).text("new text");
});
$("#addButton").click(function() {
$(".list").append(
$('<li>').append($('<span>').append("added li")));
});​
Thank you for all responses.

You just need to use event-delegation, with the on() method:
$("ul").on('click','li', function() {
$(this).text("OK");
});
JS Fiddle demo.
The problem you were experiencing is that jQuery can only directly bind events to already-present elements (present at the point of event-binding); the on() approach binds the action to the element to which the new content is added (or an ancestor element of the newly-added elements), identifies the events to listen for 'click' (a space-separated list of events), that match the selector (li) and then the function performs the required actions.
If you're using jQuery 1.7 (or later) on() should be used, for versions of jQuery < 1.7, delegate() should be used instead (which does more or less the same thing, but reverses the event-list and the selector parameters):
$("ul").delegate('li', 'click', function() {
$(this).text("OK");
});
JS Fiddle demo.
References:
delegate().
on().

Need to use event delegation here..
Try this
$("ul").on('click' , 'li', function() {
$(this).text("OK");
});
The problem with the previous click event is that events are only attched to the current element's on the page..
But when you create a new element , no events are attached to the element.
You have two options here.. Either to delegate your event i.e; add the event listerner to the element's ancestor ..
Or add the event once the element is created..
2nd Approach
var clickEvent = function() {
$('li').unbind().on('click', function() {
$(this).text("OK");
});
}
clickEvent();
$("#addButton").click(function() {
$(".list").append(
$('<li>').append($('<span>').append("Press me - I am new!")));
clickEvent();
});​
In the second approach you are binding unbinding and binding the new event to all the elements once a new element is added..
Binding and again rebinding of events is a bad design pattern
FIDDLE
2nd APPROACH

Related

jQuery remove scroll listener after reach certain point [duplicate]

I have an input type="image". This acts like the cell notes in Microsoft Excel. If someone enters a number into the text box that this input-image is paired with, I setup an event handler for the input-image. Then when the user clicks the image, they get a little popup to add some notes to the data.
My problem is that when a user enters a zero into the text box, I need to disable the input-image's event handler. I have tried the following, but to no avail.
$('#myimage').click(function { return false; });
jQuery ≥ 1.7
With jQuery 1.7 onward the event API has been updated, .bind()/.unbind() are still available for backwards compatibility, but the preferred method is using the on()/off() functions. The below would now be,
$('#myimage').click(function() { return false; }); // Adds another click event
$('#myimage').off('click');
$('#myimage').on('click.mynamespace', function() { /* Do stuff */ });
$('#myimage').off('click.mynamespace');
jQuery < 1.7
In your example code you are simply adding another click event to the image, not overriding the previous one:
$('#myimage').click(function() { return false; }); // Adds another click event
Both click events will then get fired.
As people have said you can use unbind to remove all click events:
$('#myimage').unbind('click');
If you want to add a single event and then remove it (without removing any others that might have been added) then you can use event namespacing:
$('#myimage').bind('click.mynamespace', function() { /* Do stuff */ });
and to remove just your event:
$('#myimage').unbind('click.mynamespace');
This wasn't available when this question was answered, but you can also use the live() method to enable/disable events.
$('#myimage:not(.disabled)').live('click', myclickevent);
$('#mydisablebutton').click( function () { $('#myimage').addClass('disabled'); });
What will happen with this code is that when you click #mydisablebutton, it will add the class disabled to the #myimage element. This will make it so that the selector no longer matches the element and the event will not be fired until the 'disabled' class is removed making the .live() selector valid again.
This has other benefits by adding styling based on that class as well.
This can be done by using the unbind function.
$('#myimage').unbind('click');
You can add multiple event handlers to the same object and event in jquery. This means adding a new one doesn't replace the old ones.
There are several strategies for changing event handlers, such as event namespaces. There are some pages about this in the online docs.
Look at this question (that's how I learned of unbind). There is some useful description of these strategies in the answers.
How to read bound hover callback functions in jquery
If you want to respond to an event just one time, the following syntax should be really helpful:
$('.myLink').bind('click', function() {
//do some things
$(this).unbind('click', arguments.callee); //unbind *just this handler*
});
Using arguments.callee, we can ensure that the one specific anonymous-function handler is removed, and thus, have a single time handler for a given event. Hope this helps others.
maybe the unbind method will work for you
$("#myimage").unbind("click");
I had to set the event to null using the prop and the attr. I couldn't do it with one or the other. I also could not get .unbind to work. I am working on a TD element.
.prop("onclick", null).attr("onclick", null)
If event is attached this way, and the target is to be unattached:
$('#container').on('click','span',function(eo){
alert(1);
$(this).off(); //seams easy, but does not work
$('#container').off('click','span'); //clears click event for every span
$(this).on("click",function(){return false;}); //this works.
});​
You may be adding the onclick handler as inline markup:
<input id="addreport" type="button" value="Add New Report" onclick="openAdd()" />
If so, the jquery .off() or .unbind() won't work. You need to add the original event handler in jquery as well:
$("#addreport").on("click", "", function (e) {
openAdd();
});
Then the jquery has a reference to the event handler and can remove it:
$("#addreport").off("click")
VoidKing mentions this a little more obliquely in a comment above.
If you use $(document).on() to add a listener to a dynamically created element then you may have to use the following to remove it:
// add the listener
$(document).on('click','.element',function(){
// stuff
});
// remove the listener
$(document).off("click", ".element");
To remove ALL event-handlers, this is what worked for me:
To remove all event handlers mean to have the plain HTML structure without all the event handlers attached to the element and its child nodes. To do this, jQuery's clone() helped.
var original, clone;
// element with id my-div and its child nodes have some event-handlers
original = $('#my-div');
clone = original.clone();
//
original.replaceWith(clone);
With this, we'll have the clone in place of the original with no event-handlers on it.
Good Luck...
Updated for 2014
Using the latest version of jQuery, you're now able to unbind all events on a namespace by simply doing $( "#foo" ).off( ".myNamespace" );
Best way to remove inline onclick event is $(element).prop('onclick', null);
Thanks for the information. very helpful i used it for locking page interaction while in edit mode by another user. I used it in conjunction with ajaxComplete. Not necesarily the same behavior but somewhat similar.
function userPageLock(){
$("body").bind("ajaxComplete.lockpage", function(){
$("body").unbind("ajaxComplete.lockpage");
executePageLock();
});
};
function executePageLock(){
//do something
}
In case .on() method was previously used with particular selector, like in the following example:
$('body').on('click', '.dynamicTarget', function () {
// Code goes here
});
Both unbind() and .off() methods are not going to work.
However, .undelegate() method could be used to completely remove handler from the event for all elements which match the current selector:
$("body").undelegate(".dynamicTarget", "click")
I know this comes in late, but why not use plain JS to remove the event?
var myElement = document.getElementById("your_ID");
myElement.onclick = null;
or, if you use a named function as an event handler:
function eh(event){...}
var myElement = document.getElementById("your_ID");
myElement.addEventListener("click",eh); // add event handler
myElement.removeEventListener("click",eh); //remove it
This also works fine .Simple and easy.see http://jsfiddle.net/uZc8w/570/
$('#myimage').removeAttr("click");
if you set the onclick via html you need to removeAttr ($(this).removeAttr('onclick'))
if you set it via jquery (as the after the first click in my examples above) then you need to unbind($(this).unbind('click'))
All the approaches described did not work for me because I was adding the click event with on() to the document where the element was created at run-time:
$(document).on("click", ".button", function() {
doSomething();
});
My workaround:
As I could not unbind the ".button" class I just assigned another class to the button that had the same CSS styles. By doing so the live/on-event-handler ignored the click finally:
// prevent another click on the button by assigning another class
$(".button").attr("class","buttonOff");
Hope that helps.
Hope my below code explains all.
HTML:
(function($){
$("#btn_add").on("click",function(){
$("#btn_click").on("click",added_handler);
alert("Added new handler to button 1");
});
$("#btn_remove").on("click",function(){
$("#btn_click").off("click",added_handler);
alert("Removed new handler to button 1");
});
function fixed_handler(){
alert("Fixed handler");
}
function added_handler(){
alert("new handler");
}
$("#btn_click").on("click",fixed_handler);
$("#btn_fixed").on("click",fixed_handler);
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn_click">Button 1</button>
<button id="btn_add">Add Handler</button>
<button id="btn_remove">Remove Handler</button>
<button id="btn_fixed">Fixed Handler</button>
I had an interesting case relevant to this come up at work today where there was a scroll event handler for $(window).
// TO ELIMINATE THE RE-SELECTION AND
// RE-CREATION OF THE SAME OBJECT REDUNDANTLY IN THE FOLLOWING SNIPPETS
let $window = $(window);
$window.on('scroll', function() { .... });
But, to revoke that event handler, we can't just use
$window.off('scroll');
because there are likely other scroll event handlers on this very common target, and I'm not interested in hosing that other functionality (known or unknown) by turning off all of the scroll handlers.
My solution was to first abstract the handler functionality into a named function, and use that in the event listener setup.
function handleScrollingForXYZ() { ...... }
$window.on('scroll', handleScrollingForXYZ);
And then, conditionally, when we need to revoke that, I did this:
$window.off('scroll', $window, handleScrollingForXYZ);
The janky part is the 2nd parameter, which is redundantly selecting the original selector. But, the jquery documentation for .off() only provides one method signature for specifying the handler to remove, which requires this middle parameter to be
A selector which should match the one originally passed to .on() when attaching event handlers.
I haven't ventured to test it out with a null or '' as the 2nd parameter, but perhaps the redundant $window isn't necessary.

jquery issue with on and live

I have the following code:
var $reviewButton = $('span.review_button');
$reviewButton
.live('click',
function(){
$('#add_reviews').show();
}
)
Later in the script, I use an AJAX call to load some content and another instance of $('span.review_button') enters the picture. I updated my code above to use '.live' because the click event was not working with the AJAX generated review button.
This code works, as the .live(click //) event works on both the static 'span.review_button' and the AJAX generated 'span.review_button'
I see however that .live is depracated so I have tried to follow the jquery documentations instructions by switching to '.on' but when I switch to the code below, I have the same problem I had before switching to '.live' in which the click function works with the original instance of 'span.review_button' but not on the AJAX generated instance:
var $reviewButton = $('span.review_button');
$reviewButton
.on('click',
function(){
$('#add_reviews').show();
}
)
Suggestions?
The correct syntax for event delegation is:
$("body").on("click", "span.review_button", function() {
$("#add_reviews").show();
});
Here instead of body you may use any static parent element of "span.review_button".
Attention! As discussed in the comments, you should use string value as a second argument of on() method in delegated events approach, but not a jQuery object.
This is because you need to use the delegation version of on().
$("#parentElement").on('click', '.child', function(){});
#parentElement must exist in the DOM at the time you bind the event.
The event will bubble up the DOM tree, and once it reaches #parentElement, it is checked for it's origin, and if it matches .child, executes the function.
So, with this in mind, it's best to bind the event to the closest parent element existing in the DOM at time of binding - for best performance.
Set your first selector (in this case, div.content) as the parent container that contains the clicked buttons as well as any DOM that will come in using AJAX. If you have to change the entire page for some reason, it can even be change to "body", but you want to try and make the selector as efficient as possible, so narrow it down to the closest parent DOM element that won't change.
Secondly, you want to apply the click action to span.review_button, so that is reflected in the code below.
// $('div.content') is the content area to watch for changes
// 'click' is the action applied to any found elements
// 'span.review_button' the element to apply the selected action 'click' to. jQuery is expecting this to be a string.
$('div.content').on('click', 'span.review_button', function(){
$('#add_reviews').show();
});

jQuery .live() vs .on() method for adding a click event after loading dynamic html

I am using jQuery v.1.7.1 where the .live() method is apparently deprecated.
The problem I am having is that when dynamically loading html into an element using:
$('#parent').load("http://...");
If I try and add a click event afterwards it does not register the event using either of these methods:
$('#parent').click(function() ...);
or
// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...);
What is the correct way to achieve this functionality? It only seems to work with .live() for me, but I shouldn't be using that method. Note that #child is a dynamically loaded element.
Thanks.
If you want the click handler to work for an element that gets loaded dynamically, then you set the event handler on a parent object (that does not get loaded dynamically) and give it a selector that matches your dynamic object like this:
$('#parent').on("click", "#child", function() {});
The event handler will be attached to the #parent object and anytime a click event bubbles up to it that originated on #child, it will fire your click handler. This is called delegated event handling (the event handling is delegated to a parent object).
It's done this way because you can attach the event to the #parent object even when the #child object does not exist yet, but when it later exists and gets clicked on, the click event will bubble up to the #parent object, it will see that it originated on #child and there is an event handler for a click on #child and fire your event.
Try this:
$('#parent').on('click', '#child', function() {
// Code
});
From the $.on() documentation:
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().
Your #child element doesn't exist when you call $.on() on it, so the event isn't bound (unlike $.live()). #parent, however, does exist, so binding the event to that is fine.
The second argument in my code above acts as a 'filter' to only trigger if the event bubbled up to #parent from #child.
$(document).on('click', '.selector', function() { /* do stuff */ });
EDIT: I'm providing a bit more information on how this works, because... words.
With this example, you are placing a listener on the entire document.
When you click on any element(s) matching .selector, the event bubbles up to the main document -- so long as there's no other listeners that call event.stopPropagation() method -- which would top the bubbling of an event to parent elements.
Instead of binding to a specific element or set of elements, you are listening for any events coming from elements that match the specified selector. This means you can create one listener, one time, that will automatically match currently existing elements as well as any dynamically added elements.
This is smart for a few reasons, including performance and memory utilization (in large scale applications)
EDIT:
Obviously, the closest parent element you can listen on is better, and you can use any element in place of document as long as the children you want to monitor events for are within that parent element... but that really does not have anything to do with the question.
The equivalent of .live() in 1.7 looks like this:
$(document).on('click', '#child', function() ...);
Basically, watch the document for click events and filter them for #child.
I know it's a little late for an answer, but I've created a polyfill for the .live() method. I've tested it in jQuery 1.11, and it seems to work pretty well. I know that we're supposed to implement the .on() method wherever possible, but in big projects, where it's not possible to convert all .live() calls to the equivalent .on() calls for whatever reason, the following might work:
if(jQuery && !jQuery.fn.live) {
jQuery.fn.live = function(evt, func) {
$('body').on(evt, this.selector, func);
}
}
Just include it after you load jQuery and before you call live().
.on() is for jQuery version 1.7 and above. If you have an older version, use this:
$("#SomeId").live("click",function(){
//do stuff;
});
I used 'live' in my project but one of my friend suggested that i should use 'on' instead of live.
And when i tried to use that i experienced a problem like you had.
On my pages i create buttons table rows and many dom stuff dynamically. but when i use on the magic disappeared.
The other solutions like use it like a child just calls your functions every time on every click.
But i find a way to make it happen again and here is the solution.
Write your code as:
function caller(){
$('.ObjectYouWntToCall').on("click", function() {...magic...});
}
Call caller(); after you create your object in the page like this.
$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();
By this way your function is called when it is supposed to not every click on the page.

Why when initiating $.click() several times, and if the link is clicked once, it captures it more than once?

I have something like:
function init(){
$('.btn').click(function(){
//do something;
}
}
And when new content is added via ajax, I'm calling init(), so that click event applies to new buttons. But when I click it once, it captures several clicks (as many times as I called init()). It makes sense, but how to avoid it?
jsFiddle link: http://jsfiddle.net/s2ZAz/8/
Solutions:
* Use $.delegate() - http://api.jquery.com/delegate/
* Use $.live() - http://api.jquery.com/live/
Less preferred, but still, solutions:
* Use $.off() - http://api.jquery.com/off/ or $.unbind() - http://api.jquery.com/unbind/
click says, "for every object matching the selector, hook up this click listener". You probably want something more like delegate that says "for every object that will ever match this selector, hook up this listener".
$(document).delegate('button', 'click', function() {
});
You will still get double callbacks if you call init twice, but in this manner, you won't have to call init twice, because as new objects are added, they'll already be assigned to click listeners.
Note that document above should be replaced with the nearest persistent ancestor, as per Greg's comment below.
Demo.
Since jQuery 1.7, you can preferably use the .on() function to achieve the same effect.
Demo.
You can use the unbind method to remove the event handler (or the off method if you're using the new jQuery 1.7 syntax for attaching handlers)
Better yet, you can use the live method, to set up the event handler for any elements that are added to the page in the future and match the given selector. In this way you only have to call init once.
$("body").delegate("button", "click", function() {
alert('I\'m annoying!');
});
$('div').append("<button>Click me, I will alert twice</button><br/>");
$('div').append("<button>Click me, I will alert once</button><br/>");
$('div').append("<button>Click me, I will not alert at all</button><br/>");
Try it out
As mentioned by David, and as per liho's delegate example (loved the way the fiddle cascaded how many times the alert would pop!!), the problem is with multiple bindings, which can be solved with .live() (deprecated) or .delegate() (being phased out), or .on() (the preferred). However, it is a mistake to delegate listening to the document or even body node in terms of performance.
A better way to do this is identify an ancestor of the button that will not ever be destroyed. body is an easy choice, but it's almost always the case that we build our pages with wrapper elements of some sort, which are nested one or more levels deeper than body and therefore allow you to set fewer listeners.
HTML:
<div id="someWrapper">
<div class="somethingThatGetsDestroyed">
<button>Click Me</button>
</div>
</div>
JS using jQuery 1.7+:
$('#someWrapper').on('click', 'button', function() {
alert('Clickity-click!');
});

Is there any Prototype Javascript function similar to Jquery Live to trace dynamic dom elements?

Event.observe(window,"load",function() {
$$(".elem_classs").findAll(function(node){
return node.getAttribute('title');
}).each(function(node){
new Tooltip(node,node.title);
node.removeAttribute("title");
});
});
Using above method, I can retrieve all elements having ".elem_class" and apply some javascript functions on them. But I have a modal/popup box which has some elements also having ".elem_class" and these dont get in the scope of findAll/each as they are loaded into the dom thru ajax.
How do I apply the same to dynamically loaded elements as well?
I am using Prototype Library. (I have used JQuery's Live function which keeps track of all future elements, but need to achieve something similar using Prototype)
Thanks.
As far as I know, event delegation is bot built into Prototype, but it shouldn't be too difficult to do on your own. Simply add a handler to observe the event on the body then use Event#findElement to check if it matches your selector.
Here is a sample function that sets up the delegation for you (run this on load):
/**
* event_type: 'click', 'keydown', etc.
* selector: the selector to check against
* handler: a function that takes the element and the event as a parameter
*/
function event_delegator(event_type, selector, handler) {
Event.observe(document.body, event_type, function(event) {
var elt = Event.findElement(event, selector);
if (elt != document)
handler(event, elt);
});
}
You could probably extend Element to handle this for you, streamlining everything. Hope this helps!
Edit: The hover event (or mousein/mouseout) should be a good event for a tooltip. Also, don't get all the elements on load, that's unnecessary when using event delegation. Here's a link to more about event delegation: http://www.sitepoint.com/blogs/2008/07/23/javascript-event-delegation-is-easier-than-you-think/

Categories