My website works basically with javascript. the server returns the html in a JSON array then javascript will add it to DOM.
My problem is with events.
Should I add the click event to body/window and then check if target match or add event to every element ? (the most events will be in the feed, where elements have same class):
<div id="feed_1">
<div class="like_button" data-click="something here">Like</div>
</div>
<div id="feed_2">
<div class="like_button" data-click="something here">Like</div>
</div>
note: I'm not using jQuery
If you are asking whether or not you should add an even to every element in the HTML document, or to have one event listener that specifies a target upon a click, the better way is definitely the latter.
With events that work with a large number of elements, we enforce DRY principles through the use of event delegation. This involves declaring an event listener with the event parameter, and then triggering the event onto the event target. example:
var el = document.getElementByID('container');
el.addEventListener('click', function(e) {
doSomething(e.target); // do something to the target element
});
The idea here is that your container element encompasses everything you wish to be 'clickable', however, when you click an element within the container, the event will only fire for that clicked element. This way we prevent having to define an event listener for each individual element.
Hope this helps.
Related
I have a table where i have bound all my elements with class="shift" to a click function.
Now, because I also need to use another click event on part of the element, I would like to unbind the click event on element when the mouse enters the element and rebind when i leaves (meant for some touch events and whatnot)
Now, I bind like this
$("table").on("touchstart mousedown",".shift", function(e){ ... })
But when i try to unbind on a specific element, say it has a class="selected" added to distinguish the current element i use:
$("table").off("touchstart mousedown",".shift.selected")
which does not work....
I can remove all the handlers at once, but it would be wasteful to remove all the handlers and reinsert them as soon as the mouse leaves.
So, is there a way to remove the handler on a single element after the event is bound to all current and future elements?
Thanks in advance!
You don't need to unbind the click event on the element when the mouse enters. I know, the element click event will trigger when you click an inner element with the click event bound, right ? you can stop that:
The click handler of the inner element must look like this:
$("some inner element").click(function(event) {
//That's what are you looking for ;)
event.stopPropagation();
//You code here
});
event.stopPropagation() will prevent the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
I have created a dynamic page in which i am loadin 10 element by default. after that if user scroll doun i am apppending more element to this page by js (appending data by ajax).
and on click of a tag i am doing some js work
I am using
$('.atnd_modal').click(function(){
alert("dsfds");
});
not
onclick ="function()" and i dont want to do that onclick.
Problem i am facing that this js is working perfectely for first 10 result but after that it stop working for the block i have appended by js.
how can to do it working for both the cases ??
Try jquery on() for event delegation. It will work on dynamic loaded element on DOM also.
$('body').on('click','.atnd_modal', function(){
alert("dsfds");
});
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time.
Your click event is not working because when you use click() it will attach this handler to all elements having atnd_modal class, but when new element loading in DOM that event is not attached automatically with new element. For previous elements it will work fine but for new element it won't. So here comes Delegated events. We shall attach event to parent element with on() or delegate()
If you want to bind an event to the dynamically added new elements you have to use event delegation :-
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.
Change your code like this, use Jquery On
$('body').on('click','.atnd_modal', function(){
alert("dsfds");
});
I want to do something on all clicks except on a certain element.
I've created a very simple example which demonstrates the issue: http://jsfiddle.net/nhe6wk77/.
My code:
$('body').on('click', ':not(a)', function () {
// do stuff
});
I'd expect all click to on <a> to be ignored, but this is not the case.
Am I doing something wrong or is this a bug on jQuery's side?
There's a lot going on in that code that's not obvious. Most importantly, the click event is actually attached to the body element. Since that element isn't an anchor, you'll always get the alert. (Event delegation works because the click event bubbles up from the a through all its ancestors, including body, until it reaches document.)
What you want to do is check the event.target. That will tell you the element that was actually clicked on, but the actual click event is still bound to the body element:
$('body').on('click', function (e) { // e = event object
if ($(e.target).is(':not(a)')) {
alert('got a click');
}
});
http://jsfiddle.net/y3kx19z7/
No this is not a bug but rather intended behaviour.
The event bubbles all the way up. By clicking the a node, you are still triggering it's parents event from the div node.
Read more about event bubbling in the W3C DOM Specification. Just search for "bubble".
You need to stop the event propagation of the a nodes. i.e.:
$('body').on('click', ':not(a)', function () {
// do something effectively
alert('you should not see me when clicking a link');
});
$("a").click(function( event ) {
// do nothing effectively, but stop event bubbling
event.stopPropagation();
});
JSFiddle: http://jsfiddle.net/nhe6wk77/6/
It's working as intended, here's why!
Use of the :not() selector is honored in delegated events, but it's an uncommon practice because of how events bubble up the DOM tree potentially triggering the handler multiple times along the way.
The jQuery API Documentation states that:
jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.
Notice the phrase "and runs the handler for any elements along that path matching the selector".
In your example, jQuery is accurately not running the handler on the a element, but as the event bubbles up the tree, it runs the handler for any element that matches :not(a), which is every other element in the path.
Here is a clear example showing how this works: http://jsfiddle.net/gfullam/5mug7p2m/
$('body').on('click', ':not(a)', function (e) {
alert($(this).text());
});
<div class="outer">
<div class="inner">
Click once, trigger twice
</div>
</div>
<div class="outer">
<div class="inner">
<button type="button">Click once, trigger thrice</button>
</div>
</div>
Clicking on the link in the first block of nested divs, will start the event bubbling, but the clicked a element — a.k.a. the event target — doesn't trigger the handler because it doesn't match the :not(a) selector.
But as the event bubbles up through the DOM, each of its parents — a.k.a the event currentTarget — triggers the handler because they do match the :not(a) selector, causing the handler to run twice. Multiple triggering is something to be aware of since it may not be a desired result.
Likewise, clicking on the button in the second block of nested divs, will start the event bubbling, but this time the event target does match the :not(a) selector, so it triggers the handler immediately. Then as the event bubbles up, each of its parents matching the selector triggers the handler, too, causing the handler to run three times.
As others have suggested, you need to either bind an alternate handler that stops propagation on a click events or check the event target against the :not(a) selector inside your handler instead of the delegated selector.
$("body").click(function(e) {
if($(e.target).is('a')){
e.preventDefault();
return;
}
alert("woohoo!");
});
check the target of the click. this way you dont need to bind another event.
updated fiddle
I need to attach a JavaScript click listener to an add new record confirmation on a DevExpress gridview.
I can't use a regular click event listener as it's loaded via AJAX integrated into the control. I also have no access to the button's code so am unable to extend it.The only thing I do have is the button name.
Ideally I want to listen for the appearance of the button on the DOM and then attach the listener, is there any way to do this?
You do not need to wait for the appearance of the button in the DOM.
Just use a delegated event handler attached to a non-changing ancestor of the dynamic elements.
e.g.
$(document).on('click', '.someclass', function(){
///
});
If you only have the element name for the button use an attribute selector:
e.g.
$(document).on('click', '[name="somename"]', function(){
///
});
Delegated events work by listening for events bubbling up to a non-changing ancestor (document is the default if nothing closer is available). It then applies the selector at event time (not at event registration time). It then calls the function for any matching element that caused the event.
The end result is that it will work with elements that may exist later, when the event occurs.
Note: if nothing is closer to the dynamic content, use document, but do not use 'body' as styling can make it have a zero height and delegated mouse events will not work!
I am unsure as to how to approach this problem.
I have some buttons made in the HTML with some data attributes added to them. These buttons have a class called roleBtn which will call my jQuery roleBtnClicked function and grab the variables in the HTML's data attributes.
$(".roleBtn").click(roleBtnClicked);
function roleBtnClicked(event){
reg.roleName = $(this).html(); /* Get role name: Actor */
reg.blueBtn = $(this).data('blue'); /* Get blue-btn-1 */
reg.the_Num = $(this).data('num'); /* Get the number */
reg.modal_ID = $(this).data('modal'); /* Get modal-1 */
Now using this information, after the roleBtn is clicked a modal window will come up, I then have a doneButton which will close the modal window and use the variables from the data attributes to then generate new HTML on the fly. This new HTML will contain a button with the class of blueBtn.
My problem is that my click function for blueBtn won't work on a blue button that was created on the fly. It will work on a div that already has the class blueBtn before hand, but doesn't work if it was created on the fly.
Do you know a workaround to this? Or am I missing something simple?
After the doneButton is clicked I have another function that creates the new HTML including the blueBtns on the fly:
$('.selected_row .choices-col-left').append('<div class="blueBtn-holder" id="blueBtnHolder-'+theNum+'"><div class="blueBtn" id="'+blueBtn+'" row="'+rowName+'" modal="'+modal_ID+'" num="'+theNum+'">'+roleName+'</div></div>');
My blue button click function which doesn't work
$(".blueBtn").click(blueBtnClicked);
function blueBtnClicked(event){
alert("Where are you blueBtn on the fly?");
console.log("Where are you blueBtn on the fly?");
};
Try this:-
You need Event delegation for dynamically created elements using .on()
$(".selected_row").on('click', '.blueBtn', blueBtnClicked);
function blueBtnClicked(event){
alert("Where are you blueBtn on the fly?");
console.log("Where are you blueBtn on the fly?");
};
Demo
When you just bind a click event, it will be only bound to the existing DOM elements, so you want to bind the event to the parent element and later any elements you add with the same selector with that container will have the event available by delegation.
From Jquery Docs
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. This element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.
That's because you have to reassign event handlers for newly created items.
A better approach would be using .on on the container object, and then specify the child objects that should respond to the clicks:
$(".container").on('click', '.blueBtn', blueBtnClicked);
This way even if you ad objects on the fly, they will still respond. This is actually a lot more efficient way of handling that, because you only create one event handler as oppose to many. This is actually called event delegation.
Remember that when you do $(selector).click, you're telling jQuery to find all elements matching selector and assign the specific "click handler" to them. This does not happen again when you create new objects, because you're not telling jQuery to handle every future object as well (jQuery will not be aware of you adding a new button and will not assign a handler to it).