I am finding it difficult to synchronize blur and click events. The scenario is as follows: I have a page in which i have a textbox and a button. Now I have a blur event handler for the textbox, which basically makes an AJAX request and updates some part of the page. Also I have a click handler for the button which does some other job.
Now the problem here is that since I have a blur event handler on the textbox, when I enter something in the text box and directly click the button, it fires both blur and click events (as expected). The problem is synchronizing the two since the click handler should only execute once the blur handler has returned (if there was any blur event).
Sample code is as follows:
$('#textbox').on('blur', function(){
//make an ajax request
});
$('#btn').on('click',function(){
//wait for the blur event to finish(if any)
// then execute the code
})
Try something like this:
http://jsfiddle.net/8m7j5/2/
var blurring = [];
var expecting = false;
$(document).ready(function () {
$('#textbox').on('blur', function () {
// make an ajax request
console.log("TEXTBOX BLURRED");
blurring.push(1); // Flag a new blur event
$.ajax({
url: "/echo/json/",
complete: function () {
setTimeout(function () { // Simulate AJAX request taking 2 seconds
console.log("AJAX REQUEST COMPLETE");
blurring.pop(); // Flag completed blur event
checkClick();
}, 2000);
}
});
});
$('#btn').on('click', function () {
// wait for the blur event to finish(if any)
// then execute the code
console.log("ACTUALLY CLICKED BUTTON");
expecting = true;
checkClick();
});
});
function checkClick() {
if (expecting && blurring.length < 1) {
console.log("CHECKING: EXPECTING CLICK AND NO MORE BLUR EVENTS");
expecting = false;
clickFunction();
} else {
console.log("CHECKING: EITHER NOT EXPECTING OR BLUR EVENT(S) STILL OCCURRING");
}
}
function clickFunction() {
console.log("EXECUTING CLICK FUNCTION");
// Put your actual click code here
}
What you actually want to happen when the button is clicked, put in clickFunction.
The code from ianpgall a bit improved:
var functionsToCall = [];
var ajaxRunning = false;
$(document).ready(function(){
$('#textbox').on('blur', function(){
ajaxRunning = true;
console.log("START AJAX REQUEST");
$.ajax({
url: "/echo/json/",
complete: function () {
setTimeout(function () { // Simulate AJAX request taking 2 seconds
console.log("AJAX REQUEST COMPLETE");
ajaxRunning = false;
fireStackedCalls();
}, 5000);
}
});
})
$('#btn').on('click',function(){
if(ajaxRunning === true) {
functionsToCall.push('clickFunction()');
} else {
clickFunction();
}
});
function fireStackedCalls() {
while(functionsToCall.length > 0) {
toCall = functionsToCall.pop();
eval(toCall);
}
}
function clickFunction() {
console.log("EXECUTING CLICK FUNCTION");
// Put your actual click code here
}
});
Now every call of the clickFunction is recorded and executed if the ajax request is done.
Related
I list of users in a html table that is dynamically created on page load. Each row has an inline button and each button has onclick="functionName(userId)", calls the following functions:On click show the bootstrap model pop up and then after starts calling ajax. The problem is stopping the ajax calls after user has closed model,and if user clicks on another row/user pass the current userId. for some reason, sometimes ajax calls stop and sometimes dont. Previous userId is also being saved somewhere which is resulting double or triple calls in a given interval. Thank you for your insights.
//This function gets called from each row passing its userId:
var timer = null;
function RTLS(id) {
$('#RTLSModal').modal('show');
window.clearTimeout(timer);
$('#RTLSModal').on('hidden.bs.modal',
function() {
window.clearTimeout(timer);
timer = 0;
$('#RTLSModal .modal-body').html("");
$('#RTLSModal').data('bs.modal', null);
});
$('#RTLSModal').on('shown.bs.modal',
function () {
GetRealTimeScans(id);
});
}
function GetRealTimeScans(id) {
var html = '';
$.ajax({
url: '/api/v1/computers/GetRealTimeKeys?computerId=' + id,
typr: "GET",
contentType: "application/json;charset=UTF-8",
dataType: "json",
success: function (scans) {
if (scans.length > 0) {
$.each(scans,
function (index, value) {
//create html
});
$('#RTLSModal .modal-body').html(html);
} else {
html += '<div class=""><h3 style="text-align: center;">No one around</h3></div>';
$('#RTLSModal .modal-body').html(html);
}
},
complete: function () {
timer = setTimeout('GetRealTimeScans('+id+')', 10000);
}
});
}
So abort the Ajax call so it stops
var timer = null;
var ajaxCall;
function cleanUp () {
if (timer) window.clearTimeout(timer);
if (ajaxCall) ajaxCall.abort()
}
and when you make the call
cleanUp()
ajaxCall = $.ajax({})
.done( function () {
ajaxCall = null
timer = window.setTimeout(function(){}, 10000)
});
And when you bind the events to the modal, you need to remove the previous event handler.
$('#RTLSModal')
.off('hidden.bs.modal shown.bs.modal')
.on('hidden.bs.modal', function() {})
.on('shown.bs.modal', function() {});
I have a button. onclick I am changing the class of that button but when I double click its changing class. All my functionality depend on current class
how to disable double click or make the request complete on first click.
function data() {
lastScrollTop = 0;
document.getElementById("expand-dataset-btn").disabled = false;
var id = event.target.id
var allChildern = null
if(!$(".id_"+event.target.id).hasClass('minus-symbol')){
$(".id_"+event.target.id).removeClass('plus-symbol').addClass('minus-symbol')
$.ajax({
},
success : function(result) {
}
});
}else{
$(".id_"+event.target.id).addClass('plus-symbol').removeClass('minus-symbol')
$.ajax({
},
success : function(result) {
}
});
}
}
Calling function from controller like below
htmlDataId += "<a onclick=\"data()\" title='View' id="+row[primaryField]+">
what you need is "throttle" function or "debounce" function.
Throttling is a means by which we can limit the number of times a function can be called in a given period. For instance, we may have a method that should be called no more than 5 times per second.
you can either use underscore underscore official website
or
you can use the following codes:
/*trigger specific eventhandler when the event is idle for specific time*/
function debounce(fn, delay, self) {
var timer = null;
return function () {
var context = self ? self : this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
};
}
//use in the following way
$input.on('click',debounce(clickCallback,250));
then if the second "click" event triggered within 250ms, it will be ignored
You should wait for ajax to complete
function data() {
lastScrollTop = 0;
document.getElementById("expand-dataset-btn").disabled = false;
var id = event.target.id;
var allChildern = null;
if($(".id_"+ id).hasClass("disable"))
{
event.preventDefault();
}
if(!$(".id_"+ id).hasClass('minus-symbol')){
//make control disable
$(".id_"+ id).addClass('disabled');
$.ajax({
},
success : function(result) {
//change here after success
$(".id_"+ id).removeClass('plus-symbol').addClass('minus-symbol');
//remove control disable
$(".id_"+ id).removeClass('disabled');
});
}else{
//make control disable
$(".id_"+ id).attr('disabled', true);
$.ajax({
},
success : function(result) {
//change here after success
$(".id_"+ id).addClass('plus-symbol').removeClass('minus-symbol');
//remove control disable
$(".id_"+ id).attr('disabled', false);
}
});
}
}
My _() function takes a HTML element ID and returns document.getElementById(str). Below I have many eventListeners that either listen for a button click or keyboard event. However since this JS file is shared among many pages, some HTML Elements do not exist for certain pages, thus the addEventListener() function spits out an error and terminates the execution everytime it tries to bind a event listener to a non-existent HTML Element. How can I prevent this from happening and let the code execution continue? In other words, how can I catch these errors?
function _(str) {
var k = document.getElementById(str);
if(k){
return document.getElementById(str);
} else {
return false;
}
}
document.addEventListener("DOMContentLoaded", function () {
//Button Event Listeners
_("commentlink").addEventListener("click", showCommentBox);
_("help_retract").addEventListener("click", function () {
$(".help_box").toggle(500);
_("commentlink").style.display = "block";
$("#commentbox").hide();
})
_("help_link").addEventListener("click", function () {
$("#help_box").toggle(500);
});
_("q-help-link").addEventListener("click", function (){
$("#q-help").toggle(500);
});
_("comment-textbox").addEventListener("keyup", checkCharLength);
_("submit-comment").addEventListener("click", submitComment);
_("voteUp").addEventListener("click", function () {
submitVote(1);
})
_("voteDown").addEventListener("click", function () {
submitVote(-1);
})
//Automatic Events:
if (checkCookie("comm_sub")) {
showCommentBox();
}
});
Try adding this function:
window.onerror = function(){
return true;
}
If that doesn't work, surround each .addEventListener with:
try {
// .addEventListener here
} catch (e) { // Ignore Errors }
So when someone hits Reply, I am attempting to pop-up a form to type your response. Once the form is submitted, it disappears until the next time you hit Reply.
This is working except after the 1st time, I am submitting the information twice. If I do it a third time, the form submits three times. Essentially what is happening is the previous form doesn't seem to be resetting after I hide it again.
I checked this website/google and have tried using reset() but it didn't work. Below is the code:
$(document).on('click', '.secretfeed button', function () {
var message_id = $(this).attr('name');
$(".comment_box").show();
$("#m_id").val(message_id);
var value = document.getElementById("m_id").value;
$('#comment_form').submit(function (e) {
e.preventDefault();
var commentData = $(this).serialize();
$.post('../../process_comment.php', commentData, processData);
function processData(data) {
//$('comment_form').reset()
$(".comment_box").hide();
$('#comment_form')[0].reset();
RefreshFeed();
}
});
});
Rather than initializing the submit function on every click, move it outside the click function. jQuery may be creating an instance of it for each click.
$('#comment_form').submit(function (e) {
e.preventDefault();
var commentData = $(this).serialize();
$.post('../../process_comment.php', commentData, processData);
function processData(data) {
//$('comment_form').reset()
$(".comment_box").hide();
$('#comment_form')[0].reset();
RefreshFeed();
}
});
$(document).on('click', '.secretfeed button', function () {
var message_id = $(this).attr('name');
$(".comment_box").show();
$("#m_id").val(message_id);
var value = $("#m_id").val();
});
The alternative is to unbind the click function before reusing it.
We want a reusable way to handle the state. We will save the state of the button in a boolean which gets turned on and off depending on the status of the request. The pattern is the following:
var isSending = false;
function onSubmit() {
isSending = true;
// Send data
}
function onComplete() {
// done sending data
isSending = false;
}
if (!isSending) {
onSubmit();
}
// When data sending is finished:
onComplete();
The above can be encapsulated in a more functional way that uses promises to manage the state. (jQuery AJAX functions all return a promise-like object):
function oneAtATimeFunction(promisedFunction) {
var pendingPromise;
function reset() { pendingPromise = null; }
return function() {
if (pendingPromise) { return pendingPromise; }
pendingPromise = promisedFunction.apply(promisedFunction, arguments)
.always(reset);
return pendingPromise;
}
}
function submitForm() {
return $.ajax({
url: '/foo',
method: 'POST',
data: { data: 'from form' }
});
}
$('#submit-button').on('click', oneAtATimeFunction(submitForm));
Adding a little flare to the UI We can add a way to turn on and off the submit button. First we will define a helper function to handle the on and off state:
function buttonEnable(enabled) {
$('#submit-button').attr('disabled', !enabled);
}
buttonEnable(false); // disable the button
buttonEnable(true); // enable the button
Putting it all together:
function onClick() {
buttonEnable(false);
return onSubmit()
.always($.proxy(buttonEnable, null, true));
// The above is also the same as:
// .always(function() { buttonEnable(true); });
}
$('#submit-button').on('click', oneAtATimeFunction(onClick));
To see this in action here is a JSBin example.
I have a query plugin I'm working on and I certain functions after ajax content has loaded. The problem is that let's say I re-initiate it 15 times, a click event will then fire 15 times when it's only clicked once.
Is there a way so it doesn't keep piling up? I'm calling addToCart onload and also from itemDetail after the ajax return
thanks!
function addToCart()
{
$(options.add_to_cart).click(function ()
{
event.preventDefault();
var id = $(this).attr('id');
store_item_id_val = id.replace('store-item-id-', '');
var quantity = $('.quantity-' + store_item_id_val);
if (quantity.val() < 1)
{
showError('Please enter a quantity of 1 or more.');
$(quantity).val(1);
return this;
}
$.post($(this).attr('href'),
{ store_item_id: store_item_id_val, quantity: quantity.val() },
function (data)
{
var result = jQuery.parseJSON(data);
renderCart(result);
});
});
return this;
}
function itemDetails()
{
$('.item-details').click(function ()
{
event.preventDefault();
var url = $(this).attr('href');
$.getJSON(url, function (result)
{
$('.modal-title').empty().html(result.title);
$('.modal-content').empty().html(result.html);
$('#modal').slideDown(100);
$('.ui-button').button();
addToCart();
$('.modal-close').click(function ()
{
event.preventDefault();
$('#modal').hide();
});
});
});
Based on the code you provided, I would probably say that you have some other code calling itemDetails(). Each time itemDetails() is called, it ADDS another event handler for click to your .item-details. You may want to instead do:
$(document).ready(function()
{
$('.item-details').click(function ()
{
event.preventDefault();
var url = $(this).attr('href');
$.getJSON(url, function (result)
{
$('.modal-title').empty().html(result.title);
$('.modal-content').empty().html(result.html);
$('#modal').slideDown(100);
$('.ui-button').button();
addToCart();
$('.modal-close').click(function ()
{
event.preventDefault();
$('#modal').hide();
});
});
});
});
This would put the event handler on your .item-details classed items, and only fire the events once. If you have dynamic .item-details added and removed you probably should use:
$('.item-details').live('click', function() ...