Jquery firing twice in the function [closed] - javascript

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 9 years ago.
Improve this question
I am having trouble with the jquery, at the moment using v2.1, the problem is that it is firing the below twice!
I cant get this work, don't know why this is happening :(
$(document).on('click', '#task-list li.listing', function(e){
e.preventDefault();
e.stopPropagation();
alert("hello!");
$(".hiddentaskedit").show();
$(".lefthelp1").hide();
$("#task-list>li.list-group-item").removeClass("active");
$(this).addClass("active");
$("#listsbtfrm")[0].reset();
$("#datatextchk").focus();
var a = $(this).children(".view").children(".checkbox").children(".task-name1").html();
var b = $(this).children(".view").children(".checkbox").children(".task-name2").html();
var c = $(this).children(".view").children(".checkbox").children(".task-name3").html();
if(a.length>0){ $("#datatextchk").val(a); }
if(b.length>0){ $("#datatextchk2").val(b); }
if(c.length>0){ $("#datatextchk3").val(c); }
return false;
});
wv

That's because of having e.stopPropagation(); after e.preventDefault();. Try using e.preventDefault(); after e.stopPropagation();.
Since e.stopPropagation(); stops the flow to relative elements where as e.preventDefault(); stops natural flow, in other words,
e.stopPropagation(); stops the event from bubbling up the event chain.
e.preventDefault(); prevents the default action the browser makes on that event.
$(document).on('click', '#task-list li.listing', function(e){
alert("hello!");
$(".hiddentaskedit").show();
$(".lefthelp1").hide();
$("#task-list>li.list-group-item").removeClass("active");
$(this).addClass("active");
$("#listsbtfrm")[0].reset();
$("#datatextchk").focus();
var a = $(this).children(".view").children(".checkbox").children(".task-name1").html();
var b = $(this).children(".view").children(".checkbox").children(".task-name2").html();
var c = $(this).children(".view").children(".checkbox").children(".task-name3").html();
if(a.length>0){ $("#datatextchk").val(a); }
if(b.length>0){ $("#datatextchk2").val(b); }
if(c.length>0){ $("#datatextchk3").val(c); }
e.stopPropagation();
e.preventDefault();
return false;
});
If it still does not work remove e.preventDefault(); from the code i.e. =>
$(document).on('click', '#task-list li.listing', function(e){
alert("hello!");
$(".hiddentaskedit").show();
$(".lefthelp1").hide();
$("#task-list>li.list-group-item").removeClass("active");
$(this).addClass("active");
$("#listsbtfrm")[0].reset();
$("#datatextchk").focus();
var a = $(this).children(".view").children(".checkbox").children(".task-name1").html();
var b = $(this).children(".view").children(".checkbox").children(".task-name2").html();
var c = $(this).children(".view").children(".checkbox").children(".task-name3").html();
if(a.length>0){ $("#datatextchk").val(a); }
if(b.length>0){ $("#datatextchk2").val(b); }
if(c.length>0){ $("#datatextchk3").val(c); }
e.stopPropagation();
return false;
});
I have written the both functions at bottom of function as it supports other browsers(in my experiment of using it above, my function was breaking).
Update
1. As you want for dynamic (and you did not mention that before), you'll have to use live event instead of on
change this $(document).on('click', '#task-list li.listing', function(e){
to $( selector ).live( events, data, handler ){ // jQuery 1.3+
or
As suggested by AbdulJabbarWebBestow live is depreciated, either way you can use delegate
$( document ).delegate( '#task-list li.listing', "click", function(e) { // jQuery 1.4.3+
2. *More details* (source http://api.jquery.com/live/ )
jQuery attempts to retrieve the elements specified by the selector before calling the .live() method, which may be time-consuming on large documents.
Chaining methods is not supported. For example, $( "a" ).find( ".offsite, .external" ).live( ... ); is not valid and does not work as expected.
Since all .live() events are attached at the document element, events take the longest and slowest possible path before they are handled.
On mobile iOS (iPhone, iPad and iPod Touch) the click event does not bubble to the document body for most elements and cannot be used with .live() without applying one of the following workarounds:
Use natively clickable elements such as a or button, as both of these do bubble to document.
Use .on() or .delegate() attached to an element below the level of document.body, since mobile iOS does bubble within the body.
Apply the CSS style cursor:pointer to the element that needs to bubble clicks (or a parent including document.documentElement). Note however, this will disable copy\paste on the element and cause it to be highlighted when touched.
Calling event.stopPropagation() in the event handler is ineffective in stopping event handlers attached lower in the document; the event has already propagated to document.
The .live() method interacts with other event methods in ways that can be surprising, e.g., $( document ).off( "click" ) removes all click handlers attached by any call to .live()!
For pages still using .live(), this list of version-specific differences may be helpful:
Before jQuery 1.7, to stop further handlers from executing after one bound using .live(), the handler must return false.
Calling .stopPropagation() will not accomplish this.
As of jQuery 1.4 the .live() method supports custom events as well as all JavaScript events that bubble.
It also supports certain events that don't bubble, including change, submit, focus and blur.
In jQuery 1.3.x only the following JavaScript events could be bound: click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
3. As you commented on AbdulJabbarWebBestow ,
The second one is working in which we called the variable to check
"true/false" but I have lots of "click" functions do I have to use
this in every 1 of them? Is there any other universal method :) Also I
will be clicking few classes and this will not work on them ! –
Ans= Better give common class name to all of your required html elements, that you want to handle and use id for unique identification. Try using this inside function of the event, example this.id would return the id of that class name. This method is standard way for handling dynamic elements and so called universal :) .
I hope this helped you.
Please let me know for further doubts/clarification.

Try this, it is working good
$(document).unbind('click').on('click', '#task-list li.listing', function(e)
{
alert('Hellow world');
e.stopPropagation();
return false;
});
And it's definitely Javascript problem because if you hit google and search for event fire twice you will see that Angular, Jquery and backbone etc all are somewhere firing events twice or even thrice. So, it's seem that it's javascript behind this.

Related

JS/JQuery on keypress proper usage

I'm working on creating a more accessible navigation, and in particular want to use determine whether a keypress is used. While I want to figure out why this is not working for me, I also want to know the difference between several methods that do the same thing. Those methods are:
$('ul li a').on('keypress', function(e){...});
& $('ul li a').keypress(function(e) {...});
& $('ul li a').bind('keypress', function(e) {...});
What is the difference if any? And is there a 'right' one to use for this siutation? Either way, none of them are actually working for me. I have setup console logs throughout the script I have written and while the console is logging the script loading, it detects the keydown, however it does not detect the return key being pressed, the whole script looks like:
$('ul li a').on('keypress', function(e){
if(e.keyCode==13){ // return / enter key
console.log("Return Key Pressed");
}
return false;
});
Thanks!
** EDIT **
I never discovered why the return key (or down arrow) was not working, neither would trigger the keydown event in the console, but I did discover the spacebar is the best method for accessibility, the end result looked like:
$('ul li a').on('keypress', function(e){
if ((e.keyCode || e.which) == 32) { // spacebar
... script ...
return false;
}
});
Internally, .bind maps directly to .on in the current version of jQuery. (The same goes for .live.) So there is a tiny but practically insignificant performance hit if you use .bind instead.
However, .bind may be removed from future versions at any time. There is no reason to keep using .bind and every reason to prefer .on instead.
If you look in the source code for $.fn.bind you will find that it's just an rewrite function for on:
function (types, data, fn) {
return this.on(types, null, data, fn);
}
For keypress function, i don't recommend it because it work only for exsiting elements ; if element will be exist after running keypress , it will not handle new elements.
Instead you can use delegate :
$(document).delegate('ul li a','keypress',function(event){
//........
})
.on() is the preferred way to do all events in jQuery 1.7+
As of jQuery 1.7, the .on() method provides all functionality required
for attaching event handlers.
From the official docs: http://api.jquery.com/on/
Other methods of attaching events appear to be deprecated:
For help in converting from older jQuery event methods, see .bind(),
.delegate(), and .live().

return false on dynamically created element

I'm trying to prevent an event on dynamically created elements.
I tried several ways but none worked.
On deafult, a click on the div containing the class opens a menu, and I want to disable that.
This is my code (please note I'm using jQuery 1.6.4 so I'm not able to use the "on" method).
$(function() {
$( document ).delegate( "span.highlight_mkt", "click", function() {
return false;
});
});
I have tried this using the "live" method as well but without any success.
Any help would be much appreciated.
maybe this link helps you -> preventDefault
$(document).delegate("span.highlight_mkt", "click", function (e) {
e.preventDefault();
/* your code here */
});
EDIT
you tried this too?
$('span.highlight_mkt').live("click", function (e) {
e.preventDefault();
/* your code here */
});
This one should stops the event propagation:
$(function() {
$( document ).delegate( "span.highlight_mkt", "click", function(e) {
e.preventDefault();
e.stopPropagation();
return false;
});
});
What I understand from your question is you have span with highlight_mkt class in your html form with click event attached using selector or document. And you are loading using Ajax or dynamically creating other span with same class name.
So in order to prevent events on your dynamically created elements you can use .die() function with container name where you are attaching dynamically created elements as following:
$('container_selector span.highligh_mkt').die('click');
In this method click event will be fired only your elements which is not attached dynamically.
If I understand you incorrectly please clarify your question.
What you did is you are attached event handler to document element or global container using .live() jquery function. So it is not good thing to do. I will explain later.
$('body').live('click','span.hihligh_mkt', function(e){
//Your code here. Which is doing some cool staff i believe :)
});
However if you want to prevent only for dynamically created elements do following:
$('body').live('click', 'span.some_class', function(e){
// This part is needed in order to check weather it is attached dynamically
// or it is predefined html objects
if($(e.target).closest('#some_container').length==0)
{
//Your code here. Which is doing some cool staff i believe :)
}
});
So in above you will just check, does event fairing element is dynamically attached to container element or it is part original html. Of course this kind of method can be avoided if you will use event which will be attached individually to the the elements like following when DOM ready.
$('span.hihligh_mkt').live('click', funtion(e){});
In this case only elements which was exists in DOM ready will get handlers. Other dynamically attached elements will not have event handlers. Unless you are not doing deep cloning of span elements.
Another thing is here when you attaching event handler to body or other root elements it gives you slow performance. You can read about it here.
Since all .live() events are attached at the document element, events
take the longest and slowest possible path before they are handled.
You can see some example here.

Jquery events, simple clicks, how and why?

So i have some data on a page (a table) which based on some options elsewhere may get ajax reloaded from the server.
This table has buttons in it that can be clicked to make other things happen to the records in the table.
I notice that this ...
http://api.jquery.com/on/
... is the recommended approach for attaching simple event handlers to elements but that only attaches to elements that exist right now, and when I do my ajax load I lose the attached handlers.
So I started using this ... http://api.jquery.com/live/ ... and guess what, jquery team did their usual and deprecated it saying I should be using "on".
These functions behave very differently yet jquery docs say i should be using them interchangably so ...
Can someone explain the "on" equivelent of this and how I can get it to work with elements after an ajax call replacing the elements that hae previously been attached to ...
$("some selector").live('click', function (e) {
// some code code
e.preventDefault();
return false;
});
My understanding is that you would do something like ...
$("some selector").on('click', function (e) {
// some code code
e.preventDefault();
return false;
});
My guess is that I then have to re-run this code after performing my ajax call by putting this in to some sort of "initClicks" function and calling it both on page load and after the ajax call.
This seems to be a bit of a back step to me ... or have i missed something here?
Since the elements are added dynamically, you need to use event delegation to register the event handler
// New way (jQuery 1.7+) - .on(events, selector, handler)
$(document).on('click', 'some selector', function(event) {
// some code code
e.preventDefault();
return false;
});
Also, either use e.preventDefault() or return false, as:
return false = e.preventDefault() + e.stopPropagation()
So, there is no need to use both of them at same time.
When you use .on('click', function (e) {}) function, it works only for existing elements.
To handle click event on all selector elements, even for elements which will be added in future, you can use one of these functions:
$(document).on('click', "some selector", function (e) {
// some code code
e.preventDefault();
return false;
});
or:
$("body").delegate("a", "click", function () {
// your code goes here
});
For more information read article about Understanding Event Delegation
live() is not magic, it cannot see future elements, what it was doing is to attach a listener to the first root element of your page document and checks every bubbled event if it match your target selector, and when it find a match, it executes your function.
this is called event delegation
live() has been deprecated for good reasons, mainly the performance hit caused by using it.
then the jQUery team introduced the delegate() function which gave us a new way to achieve the exact result, but it has addressed the performance hit very cleverly by limiting the scope in which it will listen to bubbled events to the possible nearest parent of your now & future elements.
when they introduced the On() function, they gave you the ability to use it as normal event handler, or as a delegated handler for future elements.
so I believe they did a good job for this, giving us the flexibility to use it as we wish according to the specific scenario.
Code Examples:
using delegate():
$( "#TAGERT_ID" ).delegate( "a", "click", function() { // your code goes here}
using on() (for delegated events)
$( "#TAGERT_ID" ).on( "click", "a", function() { // your code goes here}
both ways are the same, and will handle future clicks on a which will be added in the future inside your TARGET_ID element.
TARGET_ID is an example for using ID for your selector, but you can use whatever selector according to your specific need.
The equivalent of said live is
$(document).on('click', "some selector", function (e) {
// some code code
e.preventDefault();
return false;
});
The on() is a single stop for all event handler formats, the model you used is the same as
$("some selector").click(function (e) {
// some code code
e.preventDefault();
return false;
});
which does work based event delegation.
You can never actually attach event listener to an element which does not exist in DOM yet. What live and on method do is attach listener on a parent which exists right now. live is nothing but an on attached on document itself.

Prevent click event on the clicked element?

I have a click event on the body of my document:
$("body").on('click.findElem', function(e) {
e.stopPropagation();
e.preventDefault();
self.hinter(e.target);
return false;
});
It basically catches the clicked target and does something to it. However, there are some targets that already have a click event on them, and they prevent my click from being executed at all. How do I overcome that issue? I tried unbinding it, but the click doesn't even work at all to actually execute the unbinding.
e.stopImmediatePropagation() does the job, but only if your handler executes before whatever other handler exists.
Unfortunately there is no way to insert your own handler in the first position - but you can use this nasty hack if the other handlers were bound using jQuery, too: How do you force your javascript event to run first, regardless of the order in which the events were added?
If you really need this you might want to bind an event handler in capture mode using the native DOM API: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
Capture handlers are triggered before bubble handlers (which are used by jQuery and most other scripts) so that way you have very high chance to execute your handler first.
try this and see demo
$( "body" ).on( "click", ".clickme:not(.clicked)", function( event ) {
$(this).addClass('clicked');
alert('here');
});
i tend to not use on and stick with the bind/unbind combo.
i have some pages that reload partial content and then has to rebind the events.
i tipically do something like this
$(".theobjectsiwant").unbind("click").bind("click", function() {
alert('hi there');
});
If you want/have to stick with the on() function, you shouldn't mix on() with unbind() and try a similar approach with .off("click").on("click")
Check here for a sample http://api.jquery.com/off/

How do I handle a click anywhere in the page, even when a certain element stops the propagation?

We are working on a JavaScript tool that has older code in it,
so we cannot re-write the whole tool.
Now, a menu was added position fixed to the bottom and the client would very much like it to have a toggle button to open and close the menu,
except closing needs to happen automatically when a user starts doing things out side of the menu, for example, when a user goes back into the page, and selects something or clicks on a form field.
This could technically work with a click event on the body, triggering on any click,
however there are numerous items in the older code, where a click event was handled on an internal link, and return false was added to the click function, in order for the site not to continue to the link's href tag.
So clearly, a general function like this does work, but not when clicked on an internal link where the return false stops the propagation.
$('body').click(function(){
console.log('clicked');
});
Is there a way I can force the body click event anyway,
or is there another way I can let the menu dissappear, using some global click event or anything similar?
Without having to rewrite all other clicks in the application that were created years ago.
That would be a monster task, especially since I have no clue how I would rewrite them, without the return false, but still don't let them go to their href.
Events in modern DOM implementations have two phases, capturing and bubbling. The capturing phase is the first phase, flowing from the defaultView of the document to the event target, followed by the bubbling phase, flowing from the event target back to the defaultView. For more information, see http://www.w3.org/TR/DOM-Level-3-Events/#event-flow.
To handle the capturing phase of an event, you need to set the third argument for addEventListener to true:
document.body.addEventListener('click', fn, true);
Sadly, as Wesley mentioned, the capturing phase of an event cannot be handled reliably, or at all, in older browsers.
One possible solution is to handle the mouseup event instead, since event order for clicks is:
mousedown
mouseup
click
If you can be sure you have no handlers cancelling the mouseup event, then this is one way (and, arguably, a better way) to go. Another thing to note is that many, if not most (if not all), UI menus disappear on mouse down.
In cooperation with Andy E, this is the dark side of the force:
var _old = jQuery.Event.prototype.stopPropagation;
jQuery.Event.prototype.stopPropagation = function() {
this.target.nodeName !== 'SPAN' && _old.apply( this, arguments );
};
Example: http://jsfiddle.net/M4teA/2/
Remember, if all the events were bound via jQuery, you can handle those cases just here. In this example, we just call the original .stopPropagation() if we are not dealing with a <span>.
You cannot prevent the prevent, no.
What you could do is, to rewrite those event handlers manually in-code. This is tricky business, but if you know how to access the stored handler methods, you could work around it. I played around with it a little, and this is my result:
$( document.body ).click(function() {
alert('Hi I am bound to the body!');
});
$( '#bar' ).click(function(e) {
alert('I am the span and I do prevent propagation');
e.stopPropagation();
});
$( '#yay' ).click(function() {
$('span').each(function(i, elem) {
var events = jQuery._data(elem).events,
oldHandler = [ ],
$elem = $( elem );
if( 'click' in events ) {
[].forEach.call( events.click, function( click ) {
oldHandler.push( click.handler );
});
$elem.off( 'click' );
}
if( oldHandler.length ) {
oldHandler.forEach(function( handler ) {
$elem.bind( 'click', (function( h ) {
return function() {
h.apply( this, [{stopPropagation: $.noop}] );
};
}( handler )));
});
}
});
this.disabled = 1;
return false;
});
Example: http://jsfiddle.net/M4teA/
Notice, the above code will only work with jQuery 1.7. If those click events were bound with an earlier jQuery version or "inline", you still can use the code but you would need to access the "old handler" differently.
I know I'm assuming a lot of "perfect world" scenario things here, for instance, that those handles explicitly call .stopPropagation() instead of returning false. So it still might be a useless academic example, but I felt to come out with it :-)
edit: hey, return false; will work just fine, the event objects is accessed in the same way.
this is the key (vs evt.target). See example.
document.body.addEventListener("click", function (evt) {
console.dir(this);
//note evt.target can be a nested element, not the body element, resulting in misfires
console.log(evt.target);
alert("body clicked");
});
<h4>This is a heading.</h4>
<p>this is a paragraph.</p>
If you make sure that this is the first event handler work, something like this might do the trick:
$('*').click(function(event) {
if (this === event.target) { // only fire this handler on the original element
alert('clicked');
}
});
Note that, if you have lots of elements in your page, this will be Really Very Slow, and it won't work for anything added dynamically.
What you really want to do is bind the event handler for the capture phase of the event. However, that isn't supported in IE as far as I know, so that might not be all that useful.
http://www.quirksmode.org/js/events_order.html
Related questions:
jQuery equivalent of JavaScript's addEventListener method
Emulate W3C event capturing model in IE
I know this is an old question, but to add to #lonesomeday's answer, you can do the same in vanilla JavaScript with:
document.querySelectorAll('*')
.forEach(element => element.addEventListener('click', e => {
console.log('clicked: ', e.target)
}))
This will add the listener to each element instead of to the body, and from experience this will let you execute the click event even if the page is navigating away or if there's already an onclick with stopPropagation in it.
I think this is what you need:
$("body").trigger("click");
This will allow you to trigger the body click event from anywhere.
You could use jQuery to add an event listener on the document DOM.
$(document).on("click", function () {
console.log('clicked');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
document.body.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
console.log('clicked ;)');
}
});
DEMO
https://jsfiddle.net/muratkezli/51rnc9ug/6/
My fix in Feb 2023:
To trigger a function anywhere on the page/document:
JS code:
document.onmouseup = closeMenus
'closeMenus' would be a function that turns each menu's display value to none.
Any 'mouseup' event anywhere on the document, calls the function.

Categories

Resources