My code
var post = {};
post.DivPostContent = $('.content');
post.DivPostContent.live({
mouseenter:
function()
{
var post_id = $(this).attr('data-post_id');
var content_id = $('#content' + '_' + post_id);
var link = $('#link' + '_' + post_id);
content_id.find('.post_ratings').hide();
content_id.find('.post_actions').show();
//I removed the click event on a whim, i have no clue why it works
link.unbind('click');
link.click(function(){
post.link_action(post_id);
});
},
mouseleave:
function()
{
//does something
}
});
post.link_action = function(){
//Does some Ajax request
}
Before i unbinded the click event from "Link" it called "post.link_action" four times, i was trying to get my head around why it does that. After hours of reading through my code again and again, i thought to myself, let's try removing the click event and i mistakenly put that line in the wrong place(out of frustration i guess). I ran the code, and viola! it worked! How? I have no clue.
Now my question is, why does unbinding the click event before adding it stop the process from repeating itself? I really would like to know why.
Thanks.
because every time your mouse enter the object post.DivPostContent it's binding a new click event to your link object; it triggered 4 times because you moused over 4 times.
forget .live & .click; use .on instead and bind one time & outside your mouseenter event or if you insist to bind it in there use a .off before
$elem.off("click").on("click",function() {});
but do it once and outside your mousenter
Now my question is, why does unbinding the click event before adding it stop the process from repeating itself?
The code:
link.click(function(){
post.link_action(post_id);
});
Adds a callback to the click event, if you register multiple times, like in your case onmouseenter you will end up with the same event firing multiple times.
The unbind function removes any previous callbacks to the specific event, so this why the callback fires only one time.
By the way, unless your jQuery version is 1.4.3 or less you shouldn't be unsing live.
Use on which is available from version 1.7 ore delegate which is avaiable from version 1.4.4.
Related
I'm using event delegation in the pagination for my website. When you click the < or > buttons it moves the page up or down. The problem is that if you don't release the mouse button, in a split-second it will keep repeating the click handler.
How can I make it so that this event only occurs once per-click? Here's my code:
$(document).on('mousedown', '#prev', function(event) {
// Page is the value of the URL parameter 'page'
if (page != 1) {
page--;
var state = {
"thisIsOnPopState": true
};
history.replaceState(state, "a", "?page=" + page + "");
}
// Refresh is a custom function that loads new items on the page
refresh();
});
You should use "click" event instead of "mousedown" unless you have a unavoidable reason.
But "mousedown" or "touchstart" event occurs when a user start pressing the mouse button or screen and it will not be fired until you release the button and press it again.
So I assume you are using a chattering mouse or mouses which has macro software.
change event into "click" and see if it works and in the case "click" event is not gonna solve the issue,try using another mouse.
FYI,underscore methods _.throttle or _.debounce might help to support chattering mouses.
throttle_.throttle(function, wait, [options])
Creates and returns a new, throttled version of the passed function, that, when invoked repeatedly, will only actually call the original function at most once per every wait milliseconds. Useful for rate-limiting events that occur faster than you can keep up with.
debounce_.debounce(function, wait, [immediate])
Creates and returns a new debounced version of the passed function which will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked. Useful for implementing behavior that should only happen after the input has stopped arriving. For example: rendering a preview of a Markdown comment, recalculating a layout after the window has stopped being resized, and so on.
http://underscorejs.org/
If you want to use a "delegated" event handler rather than a "direct" event handler to bubble up the event, try to use a more specific target selector than $(document) like $('.some-class') where some-class is the class name directly above the #prev element.
I would also use either the mouseup or click events instead to avoid the mousedown event firing while the mouse click is held down.
According to the API:
The majority of browser events bubble, or propagate, from the deepest,
innermost element (the event target) in the document where they occur
all the way up to the body and the document element.
Try this:
// delegated "click" listener using a more specific target selector
$('.some-class').on('click', '#prev', function(event) {})
You may want to check your HTML to see if you are using #prev multiple times. Usually, just creating the listener on the target ID element should work fine.
// direct "click" listener on an ID element
$('#prev').on('click', function(event) {})
I haven't found the answer to this question, but I have found a solution that fixes the problem. What I have done is added a conditional that only allows the click event to occur once-per-click:
var i = 0;
$(document).on('click', '#prev', function(event) {
if (page != 1 && i === 0) {
page--;
var state = {
"thisIsOnPopState": true
};
history.replaceState(state, "a", "?page=" + page + "");
i = 1;
refresh();
}
});
// Resets 'i' for the next click
$(document).on('mouseup', function() {
i = 0;
});
I am novice to jquery.
Suppose i have a list of 10 "a" tags all attached to an event handler mouseover, click, mouseout respectively.
what i want to do is iterate over all the "a" elements and trigger these events using jquery trigger.
The issue i am facing is that, these events take sometime to get triggered, hence when i run the code, all i see the result change only on the last element. And not the intermediates.
$.each($("#styles a"), function(){
console.log("picked up " + $(this));
setTimeout(qwe($(this)), 2000);
});
function qwe(obj) {
console.log(obj.attr("id"));
$.when(obj.trigger("mouseover").trigger("click").trigger("mouseout"))
.then(function () {
console.log("Changing Result Value" + $("#textTag").text());
});
}
Is there way to chain these events sequentially i.e.
Second Element's events should be trigged only when the trigger action of the first elements is complete. i tried searching over SO, but mostly articles revolve around triggering only single event.
Thanks
Create $.Deferred objects for each part of the chain, then bind them to be resolved when the events are actually triggered:
callbacks = [$.Deferred(), $.Deferred(), $.Deferred()];
obj.on('mouseover', callbacks[0].resolve);
obj.on('click', callbacks[1].resolve);
obj.on('mouseout', callbacks[2].resolve);
$.when(callbacks).done(function() { console.log('all three have fired'); });
You'd need additional logic to ensure that the order is preserved -- perhaps by using 'reject' if click isn't triggered before mouseout.
a need to speed up links with onClick attr in Phonegap app.
I would like to use Fast buttons plugin, that i found here:
https://developers.google.com/mobile/articles/fast_buttons
But i dont know, how to right use this plugin should i add this after pageinit or where?
Maybe is it quite silly question, but if i tried to find some examples, with no luck.
Could You add somebody add put here some example, how solve this problem?
Many thanks.
The touchstart (or touchend) event works great if you know the user won't be scrolling. That's actually the reason click events take so long to resolve on mobile devices, the device is waiting to see if the user is scrolling or clicking.
This will perform quite fast as there is no delay for dispatching this event:
$('#myButton').on('touchstart', function () {
//run click code now
});
You can also use jQuery Mobile's vclick event which attempts to use the native touch events but it's main problem is that you can dispatch multiple events using vclick so you should set a timeout to only allow one click at a time, for example:
var clickOk = true;
$('#myButton').on('vclick', function () {
if (clickOk === true) {
clickOk = false;
setTimeout(function () {
clickOk = true;
}, 350);
//run click code now
}
return false;
});
This will allow the event handler to run only once per 350ms which will take care of the multiple events being dispatched since the second event will be ignored.
I would set these event handlers up in a delegated event handler that runs when a pseudo-page gets initialized:
$(document).on('pageinit', '.ui-page', function () {
//bind "fast-click" event handlers now, use "$(this).find(...)" to only bind to elements of the current pseudo-page
});
Jiri If it's not too late I had to do the same thing for my app and needed to pass parameters to the function. I did it by placing the parameters in the id of the button (separarted by underscores) and using this function which grabs the id from every clicked button with a classname of "clickbutton" and splits it into the individual parameters.
$('.clickbutton').live('click', function(event) {
event.preventDefault();
var id = $(this).attr('id');
var parts = $(this).attr('id').split("_");
var item = parts[0];
var button = parts[1];
var type = parts[2];
console.log(item+button+type);
getItemCondition(item,type);
return false;
});
Still having issues with unresponsiveness from JQM click event though!
What about fastclick ?
FastClick is a simple, easy-to-use library for eliminating the 300ms delay between a physical tap and the firing of a click event on mobile browsers. The aim is to make your application feel less laggy and more responsive while avoiding any interference with your current logic.
Is it possible to remove than add back click event to specific element? i.e
I have a $("#elem").click(function{//some behaviour});, $(".elem").click(function{//some behaviour});(there are more than 1 element) while my other function getJson is executing I'd like to remove the click event from the #elem, and add it again onsuccess from getJson function, but preserve both mouseenter and mouseleave events the whole time?
Or maybe create overlay to prevent clicking like in modal windows? is that better idea?
edit :
I've seen some really good answers, but there is one detail that I omitted not on purpose. There are more than one element, and I call the click function on the className not on elementId as I stated in the original question
Rather than using unbind(), which means you'll have to rebind the same event handler later, you can use jQuery's data() facility with the ajaxStart and ajaxStop events to have your elements ignore click events during all AJAX requests:
$(".elem").click(function() {
if (!$(this).data("ajaxRequestPending")) {
// some behaviour
}
}).ajaxStart(function() {
$(this).data("ajaxRequestPending", true);
}).ajaxStop(function() {
$(this).removeData("ajaxRequestPending");
});
EDIT: This answer is also id-to-class-proof (see questioner's edit), since everything matching the selector will handle the AJAX events the right way. That's the main selling point of jQuery, and it shows.
You are looking for .unbind(). Pass it 'click' and it will destroy the click event.
I would put it just before your getJSON and re-bind the click event inside the success handler of your ajax call.
You have to do some additional scripting. There is no callback for that. Take a look over here: jQuery - How can I temporarily disable the onclick event listener after the event has been fired?
Rather than unbinding/binding the click event, you could check the state of another variable to see if it should do the action.
var MyObject = {
requestActive = false;
};
function MyJsonFunction() {
// when requesting
MyObject.requestActive = true;
//...
// when request over
MyObject.requestActive = false;
}
$("#elem").click(function{
if (MyObject.requestActive == true) {
//do something
}
});
I have a problem when assigning functions to the click event of a button in IE 7 with jQuery. Something like the following works fine in Opera but produces an infinite loop in IE:
function updateIndputFields(index, id) {
$("#reloadBtn").click(function(){ updateIndputFields(index, id) });
}
As I understand it, an infinite loop would not be the expected behavior in this situation. But I'm new to jQuery so maybe I've missed something. Anyways, what should I do to make the click event of the reloadBtn button be set to 'updateIndputFields(index, id)' in IE?
I think the key to your answer is in unbinding the event that you have already bound to the click event. I used this on IE and, if I understand what you're trying to do, it seems to do what you need:
<script type="text/javascript">
function updateIndputFields(index, id) {
$('#output').append('<p>' + index + ' : ' + id + '</p>');
$('#reloadBtn').unbind('click');
$("#reloadBtn").click(function(){ updateIndputFields(index, id) });
}
</script>
<p>reload</p>
<p>start</p>
<div id="output"></div>
Each click should output the passed parameters exactly once into the output div.
If you don't unbind the originally assigned click event, then it stays present and you attach a duplicate click event handler to the event each time it's clicked. Even in Firefox, not unbinding the event creates an interesting recursive situation.
or just use .one to bind the event
Try unbinding the event before binding it.