I have a problem with changing div's content. I make an ajax call first and receive an JSON array from server. So far, so good. Then, I want to change several div's content to what I've received from server. The problem is that content doesn't changes on the first click. Response is OK every time, I've checked with Fiddler and in my code, that I am receiving correct response. But, mystery remains why are div's on my page not changed with the first click Why I have to click twice every time? I've spend hours figuring this out, tried everything, nothing seems logical. Here's my code (project is MVC 4):
$('#btnsearch').click(function ()
{
var searchStr = $('#txtSearch').val();
var noOfPages = 1;
$.ajax({
type: "POST",
datatype: 'json',
url: $('#btnsearch').data('request-url'),/*URL from Razor's page*/
data: { pageNo: noOfPages, searchString: searchStr },/*MVC 4 call*/
success: function (jsontext)
{
$('#hiddenSearchResult').val(jsontext);
},
error: function ()
{
alert('Error when searching!');
}
});
var json = $('#hiddenSearchResult').val();
if (json.length === 0){ alert('result is empty!');
return;}/*with empty json, parsing throws error*/
json = JSON.parse(json);
if (json.Content == undefined) return;
for (var i = 0; i < json.Content.length; i++) {
switch (i) {
case 0:
$('#snippetsdivinner').html(json.Content[i].ContentString);
break;
case 1:
$('#snippetsdivinner1').html(json.Content[i].ContentString);
break;
case 2:
$('#snippetsdivinner2').html(json.Content[i].ContentString);
break;
case 3:
$('#snippetsdivinner3').html(json.Content[i].ContentString);
break;
}
}
});
The code from var json = $('#hiddenSearchResult').val() onwards is executed right after the AJAX request is started, but before it is completed, so at that time $('#hiddenSearchResult') isn't populated yet.
When you click the button for the second time, it has been populated by the completion of the AJAX request, and thus the code after your $.ajax executes as you expect.
You should move your code inside the success function to have it all executed when the AJAX request completes.
You probably need to also put all the code starting from
var json = $('#hiddenSearchResult').val();
inside the success callback of your ajax.
If you use datatype: 'json' in your ajax call, you don't have to do json = JSON.parse(json);.
And what the other answers said about putting all your code in the success callback function.
It's asynchronous, you need to wait until you have the result
$('#btnsearch').click(function ()
{
var searchStr = $('#txtSearch').val();
var noOfPages = 1;
$.ajax({
type: "POST",
datatype: 'json',
url: $('#btnsearch').data('request-url'),/*URL from Razor's page*/
data: { pageNo: noOfPages, searchString: searchStr },/*MVC 4 call*/
success: function (jsontext)
{
if (jsontext.length === 0){ alert('result is empty!');
return;
}/*with empty json, parsing throws error*/
var json = JSON.parse(jsontext);
if (json.Content == undefined) return;
for (var i = 0; i < json.Content.length; i++) {
switch (i) {
case 0:
$('#snippetsdivinner').html(json.Content[i].ContentString);
break;
case 1:
$('#snippetsdivinner1').html(json.Content[i].ContentString);
break;
case 2:
$('#snippetsdivinner2').html(json.Content[i].ContentString);
break;
case 3:
$('#snippetsdivinner3').html(json.Content[i].ContentString);
break;
}
}
},
error: function ()
{
alert('Error when searching!');
}
});
});
Related
I have a Ajax call that is working, but the success function isn't. I have a a few dates that I am inputting, after hitting submit, there should be a little alert popup saying "Data saved to the DB". The data is getting saved to the DB, however I am not getting the popup alert window.
$("#btnSubmit").bind("click", function () {
createUpdateArrays();
var url = "/Sample/Selection";
$.ajax({
type: "GET",
url: url,
data: { ids: ids, dates: dates },
success: function (success) {
if (success === true) {
alert("Success");
}
else {
alert("error");
}
}
});
ids = "";
dates = "";
});
function createUpdateArrays() {
var i = 0;
$('input.remedy-id:checkbox').each(function () {
if ($(this).is(':checked')) {
var rid = $(this).attr("id");
$('.planned-date').each(function () {
var did = $(this).attr("id");
if (did === rid) {
var date = $(this).val();
ids += rid + ",";
dates += date + ",";
}
});
};
});
};
I can't seem to understand the reason behind this..
EDIT: Before doing ANYTHING else, make sure that your server is actually returning a response to begin with.
Your success function is expecting a boolean to be returned by the server, but this is probably not what is happening. If you're returning a simple string "success" from the server, then the comparison should be if (success === "success"). This is entirely dependent on what your server is returning as a response.
Perhaps your server is returning a status code of 2xx. In either case, you can use the jQuery status code callbacks:
$.ajax({
type: "GET",
url: url,
data: { ids: ids, dates: dates },
statusCode: {
200: function(){alert("Success!")},
201: function(){alert("Success!")}
}
});
And if you don't want to do that and just want to use the success callback, try something like this:
success: function (success) {
if (success || (success.length && success.length == 0)) { // this will almost definitely evaluate to true
console.log(success) // Do this to see what is actually being returned. I guarantee it isn't a boolean value.
alert("Success");
}
else {
alert("error");
}
}
I have function that search for every element with a specific class:
$("#stepSurveyCtnId .questionCtnClass").each(function () {}
Inside each step, I check if a question is of type customer:
var type = $(this).children().data("question-type");
var isCustomerQuestion = false;
switch (type) {
case "Name":
case "Email":
isCustomerQuestion = true;
break;
}
If it's customer type, I get the next id of the customer's table from the database:
if(isCustomerQuestion) {
if (customerId == -1) {
$.ajax({
method: "POST",
url: urlCustomerCreate,
success: function (ajaxData) {
customerId = ajaxData.NumericValue;
}
});
}
}
The issue is that in the second iteration of the .each() function, customerId is still = -1, when it should be 1305 for example.
It seems that the execution don't stop in the $.ajax call, or the iterations are executed at the same time and the second iteration don't receive the customerId from the first iteration.
I'm still not 100% clear on sure on how everything is structured for you, but here is one way of handling asynchronicity in JavaScript (adapted from #ShubHam's answer)
function handleQuestion(questionElements, index, customerId) {
if (questionIndex >= questionElements.length) return;
var type = $(this).children().data("question-type");
var isCustomerQuestion = false;
switch (type) {
case "Name":
case "Email":
isCustomerQuestion = true;
break;
}
if(isCustomerQuestion) {
if (customerId == -1) {
$.ajax({
method: "POST",
url: urlCustomerCreate,
success: function (ajaxData) {
handleQuestion(questionElements, questionIndex + 1, ajaxData.NumericValue);
}
});
} else {
// Have ID now
handleQuestion(questionElements, questionIndex + 1, customerId);
}
}
}
// Go
handleQuestion($("#stepSurveyCtnId .questionCtnClass"), 0, -1);
This will only continue to the next iteration after the success callback has been triggered.
Put logic inside one function (say function 1) and ajax call inside other function.
Call ajax function from function 1. Inside success call function 1 with required params
Update (example added):
var x=['a','b','c']
var elm=document.getElementById('demo')
x.forEach(function(temp){
elm.innerHTML=elm.innerHTML+temp
})
<div id='demo'></div>
This can be converted to new logic as
var x=['a','b','c']
function sethtml(temp,length,maxlength){
//here ajax call can be placed
var elm=document.getElementById('demo')
elm.innerHTML=elm.innerHTML+temp
//inside success function of ajax
traverse(length+1,maxlength)
}
function traverse(length,maxlength){
if(length>=maxlength)
{
//all calls done next steps to perform
}else{
sethtml(x[length],length,maxlength)
}
}
traverse(0,x.length)
<div id='demo'></div>
Advice to be considered from Jamie-Day in comments: Check your logic for scope of improvement. Accessing db results in for each kind of scenario generally can be avoided(ideally it should be avoided for better user experience)
Change your ajax code. add "async: false" so that each code next to ajax will wait for ajax result
if(isCustomerQuestion) {
if (customerId == -1) {
$.ajax({
method: "POST",
async: false,
url: urlCustomerCreate,
success: function (ajaxData) {
customerId = ajaxData.NumericValue;
}
});
}
}
First, you need to think asynchronously.
Code that need to run after the ajax should be called from the success function. You also want to add error function to handle server errors.
Second, to improve speed and bandwidth I'd reduce number of AJAX calls to a single one, by joining all IDs together in a single AJAX request.
It require server-side changes and you did not provide the server-side, so I'll leave server side to you.
// Prepare ajax call
var customerData = [];
var customerCreateData = [];
$("#stepSurveyCtnId .questionCtnClass").each(function () {
var type = $(this).children().data("question-type");
var isCustomerQuestion = false;
switch (type) {
case "Name":
case "Email":
isCustomerQuestion = true;
break;
}
// Set customerId and customerCreateData
if(isCustomerQuestion) {
if (customerId == -1) {
customerCreateData.push(customerCreateData);
}
}
}); // end each
if (customerCreateData.length) {
$.ajax({
method: "POST",
url: urlCustomerCreate,
data: customerCreateData,
success: function (ajaxData) {
customerData = ajaxData.customerData;
doAmazingThingsWithCustomers(customerData);
},
error: function(jqXHR, textStatus, errorThrown) {
alert('Server error: ' + errorThrown);
}
});
}
The first A in AJAX stands for Asynchronous which means that the ajax calls would get executed and would not wait for the call to finish. This way we can let users interact with other elements on the page and provide a good user experience.
If we make the AJAX calls asynchronous by setting the async option to false, then the browser would wait for the ajax call to complete and users would not be able to interact with the elements until the call has completed. With the increase in number of calls, this blockage time would increase.
I would suggest you find a better alternative than this.
Helo,
Right now iam using a setinterval function to check every 200ms if there is a change in the mysql database to make sure a playlist in html and javascript is still up to date in order and songs.
As soon as a user changes the order, or adds a song or removes a song from the playlist table in mysql, i want a javascript function to run ONLY when a change is made and not ping my server 5 times per second.
Right now i use this code:
setInterval(function() {
contact();
},200)
where contact is like this
function contact() {
getPlaylist()
getInstructions();
setStatus();
}
function getInstructions() {
var url = BU+'player/instructions';
$.getJSON(url, function (data) {
for(var i in data) {
execute(data[i]);
}
});
}
function execute(instruction) {
switch(instruction.Name) {
case 'Next':
nextSong();
break;
case 'PP':
togglePlay();
break;
case 'Back':
back();
break;
case 'Seek':
setProgress(parseFloat(instruction.Value));
break;
case 'Setpsong':
setPlaylistsong(parseFloat(instruction.Value));
break;
}
}
function getPlaylist(edit,force) {
if(typeof(force) == 'undefined') {
force = false;
}
var url = BU+'player/playlist';
var res = false;
$.ajax({
url: url,
dataType: 'json',
async: false,
success: function (data) {
if(force || typeof($('.playlistitems').attr('data')) == 'undefined' || (new Date(data.timestamp) > new Date($('.playlistitems').attr('data')))) {
res = renderPlaylist(data,edit);
}
},
}).fail(function() {
if( $('.playlistitems .song').length > 0) {
$('.playlistitems').html('');
}
});
return res;
}
As you can see this will be a lot of traffic if there are 100 users using this program. I really want to use a method that ONLY triggers when a change is made, instead of checking 5 times per second IF a change is made.
Is this possible?
Yes Possible When ever user perform operation on database like add, edit, Delete there will be a callback function invoke.
I've been working on getting a function written to:
1) Process an input array using $.ajax calls to fill an output array (below this is inputList)
2) Below is what I have, but I'm having issues with it:
requestData(), when I call it, runs straight through to processing the outputList array without having fully populated/filled it - it puts one value into it then starts to process that, but the function still apparently runs on seperately to the subsequent processing asynchronously. I need it to be fully synchronous so that it does not return until the inputList array has been fully processed.
I'm not seeing the browser repainting the div that has its html updated on every call of the runajax() function - I'm attempting to do this with a setTimeout.
3) I've set the ajax request to be synchronous (async : false) - but this doesn't seem to help
I've tried to use jQuery's $.when to provide an ability to ensure that everything gets called in sequence - but clearly I'm not doing this correctly.
Would appreciate any help - I've asked previous related questions around this and had some useful help - but I've still not resolved this!
Thanks
//declare holding function requestData - expects a non-empty input data array named inputList
function requestData() {
//declare inner function runajax
function runajax() {
if(inputList.length > 0) {
//get first item from inputlist and shorten inputList
var data = $.trim(inputList.shift());
function getData() {
//send the data to server
return $.ajax({
url: 'sada_ajax_fetch_data.php',
cache: false,
async: false,
method: "post",
timeout: 2000,
data: {
requesttype: "getmydata",
email: encodeURIComponent(data)
}
});
}
function handleReturnedData (response) {
response = $.trim(decodeURIComponent(response));
//update the div inner html
if(response == "Failed") {
$('#fetchupdatestatus').html('There was an error retrieving the data you requested!');
} else {
$('#fetchupdatestatus').html('The item returned was '+response);
}
//add the response from ajax to the end of the outputList array
outputList.push(response);
//set up the next ajax call
var doNextBitOfWork = function () {
runajax();
};
//call setTimeout so that browser shows refreshed div html
setTimeout(doNextBitOfWork, 0);
//return
return $.when();
}
//do the next ajax request and response processing
return getData().done(handleReturnedData);
} else {
//did the last one so return
return $.when();
}
}
//kick off the ajax calls
runajax();
}
var inputList = new Array();
var outputList = new Array();
.....load +/- 100 values to be processed using ajax into array inputList
requestData();
.....process stuff in array outputList
.....etc
There was my answer with "you're doing it wrong" earlier, but then I just decided to show, how you can do it (almost) right: https://jsfiddle.net/h4ffz1by/
var request_maker = {
working: false,
queue: [],
output: [],
requestData: function(inputList) {
if (request_maker.working == true) {
return false;
}
request_maker.output = [];
request_maker.working = true;
while (inputList.length > 0) {
var data = $.trim(inputList.shift());
request_maker.queue.push(data);
}
console.log(request_maker.queue);
request_maker.doTheJob();
return true;
},
doTheJob: function() {
current_data_to_send = request_maker.queue.shift();
console.log(current_data_to_send);
if (typeof current_data_to_send != 'undefined' && request_maker.queue.length >= 0) {
$.ajax({
url: '/echo/json/',
cache: false,
method: "post",
timeout: 2000,
data: {
requesttype: "getmydata",
email: encodeURIComponent(current_data_to_send)
},
success: function(data, status, xhrobject) {
console.log(xhrobject);
request_maker.handleReturnedData(data);
},
});
} else {
request_maker.working = false;
console.log('all data has been sent');
}
},
handleReturnedData: function(response) {
console.log(response);
response = $.trim(decodeURIComponent(response));
//response= 'Failed';//uncomment to emulate this kind of response
if (response == "Failed") {
$('#fetchupdatestatus').append('There was an error retrieving the data you requested!<br/>');
} else {
$('#fetchupdatestatus').append('The item returned was ' + response + '<br/>');
request_maker.output.push(response);
}
request_maker.doTheJob();
if (request_maker.working == false) {
console.log('all requests have been completed');
console.log(request_maker.output);
}
}
}
inputList = [1, 2, 3, 4, 5, 6];
if (request_maker.requestData(inputList)) {
console.log('started working');
}
if (!request_maker.requestData(inputList)) {
console.log('work in progress, try again later');
}
Note that I've changed request path to jsfiddle's ajax simulation link and replaced html() with append() calls to print text in div. The calls are made and get handled in the same order as it is in inputList, still they don't lock user's browser. request_maker.output's elements order is also the same as in inputList.
Have in mind, that you will need to add error handling too (probably just a function that pushes 'error' string into output instead of result), otherwise any ajax error (403/404/502, etc.) will get it "stuck" in working state. Or you can use complete instead of success and check request status right there.
UPD: Answer to the question: you cannot get both. You either use callbacks and let browser repaint inbetween asynchroneous requests or you make requests synchroneous and block browser untill your code finished working.
UPD2: There actually is some information on forcing redraw, however I don't know if it will work for you: Force DOM redraw/refresh on Chrome/Mac
Following up on my question from the other day, I've run into another thing that now I've spent too many hours banging my head against.
Mostly, I'm having trouble getting the SUCCESS form to submit. I tried this as well:
jQuery form submit
Here's the code in a semi-functional fiddle:
http://jsfiddle.net/ZcgqV/
Essentially what happens is this:
I bind a method to the form's submission via onSubmit (rather than click)
On submit, it calls a remote server via jQuery .ajax() call
If the response is "PENDING", retry every 1s, nine times
On failure, don't submit the form
On success, submit the form
No matter what I try, I can't get the form to either submit when I want it to without going into a loop, or not submit immediately while it tries the remote server.
~Frustrated-trying-100-things-that-fail-ly yours...
Here's the code directly in case you dislike fiddles:
var retries = 0;
var success = false;
var token = "toki wartooth is not a bumblebee";
$(document).ready(function() {
// Attach the action to the form
$('#tehForm').attr('onSubmit', 'onsubmit_action(event)');
});
function async(fn) {
setTimeout(fn, 1000);
}
function pollServer() {
$.ajax({
type: "POST",
cache: "false",
url: "/remoteCall",
dataType: "json",
data: {
ref_token: token
}
}).done(function(data, code, jqXHR) {
switch (data.status) {
case "SUCCESS":
alert("Success");
success = true;
// --> HERE IS WHERE I WANT THE FORM TO SUBMIT <--
break;
case "PENDING":
if (retries < 9) {
retries += 1;
async(function() {
pollServer();
});
} else {
alert("Failed after 9 tries");
}
break;
case "ERROR":
alert("Error");
break;
default:
alert("Some kind of horrible error occurred");
break;
}
}).fail(function(jqXHR, textStatus) {
var statusCode = jqXHR.status;
alert("Request failed: " + statusCode + " " + textStatus);
});
}
function onsubmit_action(event) {
pollServer();
if (success === false) {
// RETURN FALSE DIDN'T WORK, SO I FOUND THIS
event.preventDefault();
}
}
EDIT:
Again, the real problem here is that I stop submission of the form. On SUCCESS, I want the form to submit. Currently if I use .submit() in SUCCESS, the AJAX is called again, starting the process over. What I want is the ACTION of the FORM to fire on SUCCESS only.
Trying to use as much of the original code as possible; here is a solution:
Post form with post back
http://jsfiddle.net/tpm7v/4/
Post form via Ajax
http://jsfiddle.net/tpm7v/5/
var retries = 0,
token = "toki wartooth is not a bumblebee",
sendRequest,
handelResponse,
postFormToServer,
$theForm = $('#tehForm');
$(document).ready(function() {
// Attach the action to the form
$theForm.bind('submit', onsubmit_action);
});
sendRequest = function() {
$.ajax({
type: "POST",
cache: "false",
url: "/remoteCall",
dataType: "json",
data: {
ref_token: token
},
success: handelResponse
});
};
postFormToServer = function() {
$.ajax({
type: "POST",
cache: "false",
url: "/remoteCallToTakFormData",
dataType: "json",
data: $form.serialize(),
success: function() {
alert('success!');
}
});
};
handelResponse = function(data, code, jqXHR) {
switch (data.status) {
case "SUCCESS":
postFormToServer();
break;
case "PENDING":
if (retries < 9) {
retries += 1;
setTimeout(sendRequest , 1000);
} else {
alert("Failed after 9 tries");
}
break;
case "ERROR":
alert("Error");
break;
default:
alert("Some kind of horrible error occurred");
break;
}
};
function onsubmit_action(evt) {
evt.preventDefault();
sendRequest();
}
Keep in mind I am going off the code your provided. You should be able to port this to work with your actual implementation. You may also want to try something like https://github.com/webadvanced/takeCommand to help clean up all the Ajax calls.
Please see my comment above for more information, but I think the problem you're seeing here is this:
Every time pollServer() fires, it's not only doing another ajax call, but it's prepping to do 9 possible ajax calls every second based on the retries loop. Since you're then setting another pollServer() call with the async() method, you're basically compounding your ajax calls out of control. You want to get the ajax call out of your retry loop, then you should at least be only getting 1 request a second, not 1, then 2, then 3, etc. I may have read the code wrong, but this is my best guess on what you're seeing.
UPDATE: I'm not sure my explanation was clear, so I thought I'd add some additional info. Basically, every time pollServer() is called and gets a PENDING response, it calls async, which registers a setTimeout(). setTimeout() keeps running every second, doing pollServer(), which then calls asynch, which registers another setTimeout() which also runs every second. Now you have two functions, which each then call setTimeout(), assuming they're still getting PENDING as a response from the server. So after 2 rounds of failed calls, you have 4 setTimeout() calls each firing an ajax call (and a new setTimeout) every second.
First off it should be: $('#tehForm').submit(onsubmit_action); or $('#tehForm').on("submit",onsubmit_action); or something like that. Never use the string form to pass a function. It uses the evil eval statement.
Next, after POST the data is already submitted. That is the whole reason for post. Why do you need all sorts of error handling in the done section. Fail should handle error handling.
If you are asking about how to try again after a timeout, try this:
Is it possible to check timeout on jQuery.post()?
I believe timeout will fall into fail.
So try this:
var retries = 0,
max_tries = 9,
success = false,
token = "toki wartooth is not a bumblebee";
$(document).ready(function() {
// Attach the action to the form
$('#tehForm').on("submit",submit_the_form);
});
function submit_the_form(e){
var dfd = $.ajax({
url : "sendTokenPolling",
data : {"token":token},
timeout : 5000 //you may want 1000, but I really think that is too short
});
dfd.done(function(){
//success, form posted
});
dfd.fail(function(){
//did not work/timedout
if (retries < max_tries){
retries += 1;
submit_the_form(e);
}
});
}