When I click a chat on my site I want the messages to be grabbed from the server so I use an $.post request like so :
$("#friendsDiv").on("click", "#aFriend", function(event){
retrieveMessages();
}
and this is what is in the retrieveMessages function
$.post("PHP/chat.php",
{
action:'retrieveMessages',
last_message: last_message,
conversation_id:conversation_id
},
function(data){
$("#messages").append(data);
last_message = $("#messages").find(".aMessage:last").attr("id");
$("#messages").animate({ scrollTop: $("#messages")[0].scrollHeight}, 1000);
}
);
The issue is that if the button is clicked very quickly multiple post requests will begin before the last_message is updated, this results in many copies of the same messages being displayed. Is there a way to prevent the button being clicked quickly or stop the post request being processed if another of the same request is already being processed?
EDIT
The #aFreind element is a DIV not a button
Typically in such situation you just disable a button until request is complete. For this you will need to provide a callback function. For example:
$("#friendsDiv").on("click", "#aFriend", function (event) {
// reference the button
var button = this;
// disable the button
this.disabled = true;
// provide a callback to be invoked when post is done
retrieveMessages(function() {
button.disabled = false;
});
});
function retrieveMessages(callback) {
$.post("PHP/chat.php", {
action: 'retrieveMessages',
last_message: last_message,
conversation_id: conversation_id
}, function (data) {
$("#messages").append(data);
last_message = $("#messages").find(".aMessage:last").attr("id");
$("#messages").animate({
scrollTop: $("#messages")[0].scrollHeight
}, 1000);
// execute callback which enables button again
callback();
});
}
Demo: http://jsfiddle.net/9t8fLdjn/
Your best bet would be to disable the button and then enable it after $.post
$("#friendsDiv").on("click", "#aFriend", function(event) {
$(this).prop('disabled', true); // disable
retrieveMessages();
});
and the retrieveMessage function
$.post("PHP/chat.php", {
action: 'retrieveMessages',
last_message: last_message,
conversation_id: conversation_id
}, function(data) {
$("#messages").append(data);
last_message = $("#messages").find(".aMessage:last").attr("id");
$("#messages").animate({
scrollTop: $("#messages")[0].scrollHeight
}, 1000);
$(this).prop('disabled', false); // enable it again
});
Instead of using on you could use the one jQuery function and bind the button again in the callback. Se http://api.jquery.com/one/
$("#friendsDiv").one("click", "#aFriend", retrieveMessages });
var retrieveMessages = function(){
$.post("PHP/chat.php", {
...
}).done(function(){
$("#friendsDiv").one("click", "#aFriend", retrieveMessages });
});
};
Related
I have this function, where I have a ajax call and in the success function, i have refresh the bootstrap table, now after the refresh i have a trigger command which i want to happen only when the refresh is done, how to do that,
success: function (result) {
console.log(result);
$('#overlay').hide();
swal({
title: result['msg'],
// text: result['text'],
type: result['type'],
showConfirmButton: true
});
$('#prospect_table').bootstrapTable('refresh');
element.parent('div').parent('div').parent('td').parent('tr').prev('tr').find('td:first').find('a').trigger('click')
}
the last event click happens at its specific time but I want to run that command only when the refresh is done,ie status=200
Thanks!
I have tried:
var evnCilck = element.parent('div').parent('div').parent('td').parent('tr').prev('tr').find('td:first').find('a').trigger('click'); // Or any other click function
$('#prospect_table').bootstrapTable('refresh', function(e){
evnCilck();
});
and
$('#prospect_table').bootstrapTable('refresh', function() {
element.parent('div').parent('div').parent('td').parent('tr').prev('tr').find('td:first').find('a').trigger('click');
});
No help from this.
You can do it like this
$('#prospect_table').bootstrapTable('refresh', function() {
element.parent('div').parent('div').parent('td').parent('tr').prev('tr').find('td:first').find('a').trigger('click');
});
Along with triggering an refresh event You also need to bind refresh eventlistener to the table like this :
var $table = $('#table');
$table.on('refresh.bs.table',function(){
// do your stuff here
element.parent('div').parent('div').parent('td').parent('tr').prev('tr').find('td:first').find('a').trigger('click');
})
You can do it by this way -
var evnCilck = element.parent('div').parent('div').parent('td').parent('tr').prev('tr').find('td:first').find('a').trigger('click'); // Or any other click function
$('#prospect_table').bootstrapTable('refresh', function(e){
evnCilck();
});
Given my below code Is there a way i can get alert when my ajax process is still in progress?
as you have already noticed code for alert will never get executed because of obvious reason that async ajax will keep happening but the value of click false will come before that and i will never be able to get alert during ajax call. Is there any way i can get alert when ajax request still in process?
<html>
<body>
<button type="button" id="submit-catalog" class="btn btn-primary">Activate</button>
</body>
</html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
var clicked = false;
$(document).on('click', '#submit-catalog', function() {
clicked = true;
//doing some ajax call which is taking time
});
if(clicked){ // never get executed
alert("button clicked")
//i am executing some function only if that button clicked
}
});
</script>
Your logic is off; here's how to do this:
var clicked;
$(document).ready(function() {
$(document).on('click', '#submit-catalog', function() {
if (clicked) {
console.log("ajax still in progress");
return false;
}
clicked = true;
console.log("starting ajax");
setTimeout(function () {
clicked = false;
console.log("ajax done");
}, 3000);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button" id="submit-catalog" class="btn btn-primary">Activate</button>
I'm not sure if this is what you're looking for, but this will prevent the ajax from firing again and again based on the variable which keeps track of the ajax progress.
It's not about Ajax. Code is getting executed top to bottom, you declared event listener on the document and it waits for action, while your 'if' statement was already processed.
This 'Alert' or any other action should be done within event listener
Also, if you want to do any action before executing ajax request you simply use beforeSend: ()=>{/*your actions*/}, and then after ajax request is done success: callback=>{/*do when done*/}
which may look like that:
$.ajax({
url: url,
method: 'POST',
beforeSend: ()=> { alert('clicked') },
success: callback=> { console.log(callback) }
})
You can also use : one() instead of on() only if you don't use the clicked variable somewhere else. You attach the event for only one trigger. At the end of the callback you reattach it.
$(document).ready(function() {
function foo(e){
setTimeout(function () {
console.log("ajax done");
$(e.delegateTarget).one('click', '#submit-catalog', foo)
},1000)
}
$(document).one('click', '#submit-catalog', foo);
});
Other solution : add class to stop the propagation thanks to delegate event
$(document).ready(function() {
$(document)
.on('click', '#submit-catalog.prevent', function(e){
e.stopImmediatePropagation();
}
.on('click', '#submit-catalog', function(){
$(e.currentTarget).addClass('prevent');
setTimeout(function () {
console.log("ajax done");
$(e.currentTarget).removeClass('prevent');
}, 1000)
});
});
$(".getDetails").click(function() {
// some stuff like fetching response from server
})
when user clicks getDetails button on UI multiple times within fraction of second , jquery generates two calls for click function and my logic fails.
I think solution to this will be to disable the button on first click itself(so that use can't click multiple times). Once i get the response or just before returning
from click method i make it enable. Is there any better solution ?
If no, how can i make button disable as soon as user click button first time. I think it needs to be done before calling click method or some where in html element ?
Java provides synchronized keyword so that only one thread enters at time inside method , i am not sure is similar thing exist in javascript or not ?
Assuming the click handler executes an AJAX request you can set the button as disabled before making the request, then enable it again once the request completes. Try this:
$(".getDetails").click(function(){}
var $btn = $(this).prop('disabled', true);
$.ajax({
url: '/foo'
success: function() {
console.log('It worked!');
},
error: function() {
console.log('It failed!');
},
complete: function() {
$btn.prop('disabled', false);
}
});
});
you can try unbinding click event and after ajax call again bind click to that class
$(".getDetails").click(function(){}
$(".getDetails").unbind('click');
// some stuff like fetching response from server
)
You can use simple flag to prevent firing your logic multiple times:
var flag = true
$(".getDetails").click(function() {
if (flag) {
flag = false;
//your logic...
//when your code ends (in after-AJAX callback for example)
flag = true;
}
});
$(".getDetails").click(function(e){
var $target = $(e.currentTarget);
// assuming the click listener is on the button
$target.prop('disabled',true);
// request, stuff...and when done:
$target.prop('disabled',false);
})
try Prevent Default and return false to avoid any other event propagation
This is solution is like semaphore or monitor
var progress = false;
$(".getDetails").on('click', function(e) {
if(!progress){
progress = true;
// some stuff like fetching response from server
//also after sucessfull fetch make true to false again
}else{
console.log('something in progress');
}
e.preventDefault();
return false;
})
This should make sure that your button will not fire the async request twice, until you have a response.
function doAjaxReq() {
/*
Add your ajax operation here
as a return value of doAjaxReq
like so:
return $.ajax({
url: '/foo',
type: 'POST',
data: data
})
Since i can't use ajax here let's smilulate
it useing a promise.
*/
promise = new Promise(function(res, rej) {
setTimeout(function(){
res({foo: "bar"});
}, 1000)
})
return promise;
}
/*
Inside here you add the click handlder
only once use `elem.one('click'...`
*/
function addClickHandler(elem) {
elem.one('click', function() {
// do your ajax request and when its
// done run `addClickHanlder` again
// i'm using `.then` because of the promise,
// you should be using `.done`.
doAjaxReq().then(function(data) {
console.log(data);
addClickHandler(elem);
});
})
}
addClickHandler($(".getDetails"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="getDetails">Get Details</button>
I have two buttons, approve (visible) and undo(not visible). Clicking approve hides the button and shows the undo button (meant as a fail safe). Clicking approve sets a 20 second delay which will submit a form if realized. However I want the un-approve button to cancel the delay. How should I best do this without removing the event handler on the form entirely?
$("button.approve").on('click', function(e){
$(this).hide();
$(this).siblings('button.undo').show();
$(this).siblings("form.update-comment.approve").delay(20000).trigger('submit');
});
$("button.undo").on('click', function(e){
$(this).hide();
$(this).siblings('button.approve').show();
$(this).siblings("form.update-comment.approve").off('submit');
});
Did you see the yellow box in the documentation ?
The .delay() method is best for delaying between queued jQuery effects. Because it is limited—it doesn't, for example, offer a way to cancel the delay—.delay() is not a replacement for JavaScript's native setTimeout function, which may be more appropriate for certain use cases.
Use a setTimeout instead
var approveTimeout;
$("button.approve").on('click', function(e){
var self = $(this);
self.hide().siblings('button.undo').show();
approveTimeout = setTimeout(function(){
self.siblings("form.update-comment.approve").trigger('submit');
}, 20000);
});
$("button.undo").on('click', function(e){
$(this).hide().siblings('button.approve').show();
clearTimeout( approveTimeout );
});
You can do it with setTimeout and clearTimeout:
function onSubmit(form) {
form.submit();
};
var delayedSubmit = null;
$("button.approve").on('click', function(e){
$(this).hide();
$(this).siblings('button.undo').show();
var thisForm = $(this).siblings("form.update-comment.approve");
delayedSubmit = setTimeout(function() {
onSubmit( thisForm );
}, 2000);
});
$("button.undo").on('click', function(e){
$(this).hide();
$(this).siblings('button.approve').show();
clearTimeout( delayedSubmit );
});
Try
var form = $("form.update-comment.approve")
, approve = $("button.approve")
, undo = $("button.undo");
form.on("submit.approved", function (e) {
// do stuff
undo.trigger("click", ["reset"])
});
approve.on('click', function (e) {
approve.hide();
undo.show();
form
.delay(20000, "approval")
.queue("approval", function () {
form.trigger('submit.approved');
}).dequeue("approval");
});
undo.hide().on('click', function (e, reset) {
form
.queue("approval", []);
undo.hide();
approve.show();
console.log(reset || "cancelled");
});
See .delay() , .queue()
var form = $("form.update-comment.approve")
, approve = $("button.approve")
, undo = $("button.undo");
form.on("submit.approved", function (e) {
e.preventDefault();
e.stopPropagation();
alert(e.namespace);
undo.trigger("click", ["reset"])
});
approve.on('click', function (e) {
approve.hide();
undo.show();
form
.delay(20000, "approval")
.queue("approval", function () {
form.trigger('submit.approved');
}).dequeue("approval");
});
undo.hide().on('click', function (e, reset) {
form
// clear queue
.queue("approval", []);
undo.hide();
approve.show();
console.log(reset || "cancelled");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<form method="POST" class="update-comment approve"></form>
<button class="approve">approve</button>
<button class="undo">undo</button>
I send data using Postmessage, but to get them right is not obtained.
My attempts:
Variant 1:
window.addEventListener("message", function(event) {
console.log(event.data);
}, false);
Variant 2:
$.bind("message", function (data) {
console.log(data);
}, false);
First variant works, but is not used jQuery. Show you how to use jQuery in this situation?
if needed sending code::
$(function() {
var iframe = $('iframe#someFrame');
setTimeout(function() {
iframe[0].contentWindow.postMessage('message to localhost', '*');
}, 1000);
});
You need to grab the originalEvent from jQuery:
$(window).on("message", function(e) {
var data = e.originalEvent.data;
});