Ajax call succesfull, second ajax call is send twice - javascript

With an AJAX call, I post a the value of a textarea to my database. The first post is always correct. But after I try to post another post, the AJAX call is executed twice. If I post again after that, the AJAX call is executed 4 times. It grows exponentially.
Here's my code:
$(".comment-box").on("keydown", function(e) {
e = e || event;
if (e.keyCode === 13 && !e.shiftKey) {
var message = $(".comment-box").val();
var id = $(".comment-box").attr("data-id");
$.ajax({
type: "post",
url: "../assets/js/ajax/comment-to-screen.php",
data: {
'message': message,
'id': id
},
success: function (data) {
$(".comment-box").val('');
$(".all-comments").append(data);
init();
return false;
}
});
e.preventDefault();
}
});
This is wrapped into a init() function,
$(document).ready(function() {
init();
function init () {
// Here is the code to post with ajax
}
});

In every successful post callback, a call to init is made. Init then attaches another handler to the textbox.
The next time enter is pressed, the two event handlers fire... ans so on
I think you can just remove the init call from the success handler

Related

Ajax form is sent twice if validation errors take place

I know about event.preventDefault() and event.stopImmediatePropagation(). But it doesn't work for me. In my case I have such ajax call:
$('#templateConfirmDialog').on('show.bs.modal', function (event) {
$(this).find('.modal-yes').click(function(){
var form = form2js('search_form', '.', true, function (node) {}, false);
var requestData = JSON.stringify(form, replacer);
var $formErrors = $('.search_form').find('.alert-danger');
event.preventDefault();
event.stopImmediatePropagation();
$.ajax({
type: 'POST',
contentType : "application/json",
url: '/fraud/template/testCreate',
data: requestData,
dataType: 'json',
success: function (data) {
$formErrors.text('');
//if no errors just reload
if (data === undefined || data.length === 0) {
location.reload();
}
else {
//else bind error messages
data.forEach(function(error) {
$('#new-' + error.field + '-error').text(error.defaultMessage);
})
}
}
});
});
My problem is that the ajax call is prevented as much times as I made attempts to input data. If I entered invalid data once - ajax is called twice. If twice - 3 times. What may be a reason of such behavior?
Every time this event happens:
$('#templateConfirmDialog').on('show.bs.modal', function (event) {
You bind a new click event handler:
$(this).find('.modal-yes').click(function(){
So if you show.bs.modal twice, then you have two click event handlers both submitting the AJAX request. Instead, just bind the click event handler once to the target clickable element, instead of binding it every time the modal is displayed.
Replace this:
$('#templateConfirmDialog').on('show.bs.modal', function (event) {
$(this).find('.modal-yes').click(function(){
//...
});
});
With this:
$('#templateConfirmDialog').find('.modal-yes').click(function(){
//...
});
Or, if that element is dynamically added to the DOM, this:
$(document).on('click', '#templateConfirmDialog .modal-yes', function(){
//...
});
That way there's just a single click event handler created when the page loads, rather than adding a new handler every time you display the modal.

Handling multithreadiing issue in javascript/jquery?

$(".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>

How to call this function automatically

Im using the following function to call an ajax request, and fill certain corresponding divs with the response:
$( function() {
$(document).ready(function() {
var postData = "";
$.ajax( {
url : \'functions/ajax_api.php?\',
type : \'post\',
data : postData,
success : function( resp ) {
$(\'#id1\').html($(\'#id1\' , resp).html());
$(\'#id2\').html($(\'#id2\' , resp).html());
}
});
return false;
});
});
The function works fine. My question is how can I call it automatically every few seconds?
I tried using window.setTimeout(function, 3000) but I couldnt set it up correctly.
use setInterval(); instead of .setTimeout()
Let me help you a little bit with that
var interval , setItinterval; // just a variables you can change names
interval = function(){
// ajax code here
}
to run it .. use:
setItinterval = setInterval(interval , 3000);
to stop it .. use
clearInterval(setItinterval);
Make sure to read setInterval for more information.
For Complete answer and Last thing I want to say when using setInterval(); Its better to use visibilitychange to avoid server error , server load or something like that
document.addEventListener('visibilitychange',function(){
if(document.visibilityState == 'visible'){
// user view the page
}else{
// user not see the page
}
});
You can use setTimeout() or setInterval, but setInterval may result in multiple simultaneous ajax calls if those calls take too long to respond. That isn't a problem if you call setTimeout() in the ajax success callback.
To use setTimeout(), first wrap your ajax call in a function. You can then add a call to setTimeout() to the ajax success callback. You also need to call the function once to start of the looping.
$(function() {
function postData() {
var postData = "";
$.ajax({
url: 'functions/ajax_api.php?',
type: 'post',
data: postData,
success: function(resp) {
$('#id1').html($('#id1', resp).html());
$('#id2').html($('#id2', resp).html());
// Call postData again after 5 seconds.
setTimeout(function() { postData(); }, 5000);
}
});
}
// Call postDate the first time to start it off.
postData();
});
Note: With the call to setTimeout in the success callback, the cycle will break if an ajax call fails. You may want that, but if you want it to act more like setInterval, you can place the call to setTimeout in the complete callback.
Here's some example code that will do it (note that it runs the function when the document loads, and then starts the interval). You can always use clearInterval(refresh_interval) if you need to stop it.
var refresh_interval;
function update_content() {
$.ajax({
url : \'functions/ajax_api.php?\',
type : \'post\',
data : postData,
success : function( resp ) {
$(\'#id1\').html($(\'#id1\' , resp).html());
$(\'#id2\').html($(\'#id2\' , resp).html());
}
});
}
$(document).ready(function() {
update_content();
setInterval(update_content, 3000);
}
The relevant documentation for using intervals is here: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval
Though you may want to look into Server Sent Events, it's probably a better solution for what you want.

values won't get updated in a function because of a ajax call

I'm writing a javascript function that should change the view of a postcard depending on which case is selected.
My problem is that the old values of the object "m_case" is getting used. If I press the button with class "case-btn" twice I get the right case selected in my postcard view. But I want it to be triggered when I press the button once.
I guess I have to do something like a callback function in the m_case.setCase() function call, but I can't get it working,
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
m_case.setCase($(this).data('case'));
// Changes the view of the postcard
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(this).toggleClass('active');
});
The setCase() function
this.setCase = function(id) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('failure');
}
}
EDIT The problem might be in my AJAX call, I have to wait till the ajax have been called. but how do I continue the first flow when my Ajax is done and not before?
SOLUTION
I made it working by adding a callback parameter and calling that function in the ajaxs complete function.
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
var that = this;
m_case.setCase($(this).data('case'), function() {
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(that).toggleClass('active');
});
});
// Sets the whole case from an id.
this.setCase = function(id, callback) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('fail big time');
}
},
complete: function() {
callback();
}
});
}
Your m_postcard.changeBackground and other calls should be in the success callback, or in another function that is called from the success callback, as those values aren't set till the async ajax call is done.
With the way your code is now the m_postcard.changeBackground and other calls are called immediately after your setCase function is done executing. This means your methods are executed before the data has arrived from the server
While the ajax is processing you probably should show a loading message on the screen to let the user know they have to wait till the processing is done. Show the message before calling the .ajax call and hide it in the success/error callbacks.
Any changes to the site content should be done from the success callback, ie changing active states, changing content, etc.

jquery $.ajax force POST

I have an ajax function that creates a link that triggers another ajax function. For some reason the second ajax function refuses to go through POST event if I've set type: "POST"
The two functionas are below:
function HandleActivateLink(source) {
var url = source.attr('href');
window.alert(url)
$.ajax({
type: "POST",
url: url,
success: function (server_response) {
window.alert("well done")
}
});
return false;
}
function HandleDeleteLink() {
$('a.delete-link').click(function () {
var url = $(this).attr('href');
var the_link = $(this)
$.ajax({
type: "POST", // GET or POST
url: url, // the file to call
success: function (server_response) {
if (server_response.object_deleted) {
FlashMessage('#form-success', 'Link Deleted <a class="activate-link" href="' + url.replace('delete', 'activate') + '">Undo</a>');
$('a.activate-link').click(function(){
HandleActivateLink($(this));
});
the_link.parent().hide();
} else {
var form_errors = server_response.errors;
alert(form_errors)
}
}
});
return false;
});
}
You'll notice HandleDeleteLink creates a new link on success, and generates a new click event for the created link. It all works butHandleActivateLink sends the request to the server as GET. I've tried using $.post instead with no luck.
Any pointers, much appreciated.
In the second event you do not inform the client to prevent the default behaviour.
One way to do this would be to change:
$('a.activate-link').click(function(){
HandleActivateLink($(this));
});
to:
$('a.activate-link').click(function(){
return HandleActivateLink($(this));
});
(This works because HandleActiveLink already returns false.)
A nicer way to do this is to pass in the event argument to the click function and tell it to preventDefault
$('a.activate-link').click(function(e){
e.preventDefault();
HandleActivateLink($(this));
});
what is your url?
btw You can't send a cross-domain post via javascript.

Categories

Resources