How do I stop all JavaScript executing from within an ajax call? - javascript

I have the following JavaScript code:
Interface.init = function()
{
$.ajax({
type: "POST",
url: "/Validate",
async: false,
success: function (data) {
if (data.Valid) {
// All good, continue executing JS code
}
else {
// Display error messsage, attempt to stop executing JS code...
return false;
}
},
error: function () {
// Display error message, attempt to stop executing JS code...
return false;
}
});
// More JavaScript functions used to load content, etc...
}
The index page calls Interface.init() on load:
<html>
<script type="text/javascript">
$(document).ready(function () {
Interface.init();
});
</script>
</html>
The ajax function is used to check if the device loading the page is valid. It is run synchronously so the page waits for the validation to complete before continuing. If the validation is successful, the ajax function is exited and the rest of the JavaScript code continues to execute. If the validation fails (or there is an error during the validation), I don't want any of the remaining JavaScript code to be executed.
I'm currently using return false, but I've also tried just return and throwing an error such as throw new Error("Validation failed") (as suggested by numerous other questions).
All these seem to do is exit the ajax function and all remaining JavaScript on the page continues to execute. Outside of the ajax function, these methods work as expected to stop the remaining code from executing, but I was hoping for this to be done from within the ajax function. Is this at all possible?

You can create an outside variable before the function and use it after it, e.g:
Interface.init = function()
{
var error = false;
$.ajax({
type: "POST",
url: "/Validate",
async: false,
success: function (data) {
if (data.Valid) {
// All good, continue executing JS code
}
else {
error = true;
}
},
error: function () {
error = true;
}
});
if (error) return;
// More JavaScript functions used to load content, etc...
}
But in fact, I recommend to not use the async=false, and instead of that, you could wrap the rest of your code in a function, and call it inside the callback, e.g:
Interface.init = function()
{
$.ajax({
type: "POST",
url: "/Validate",
success: function (data) {
if (data.Valid) {
// All good, continue executing JS code
loadAll();
}
},
error: function () {
}
});
function loadAll() {
// More JavaScript functions used to load content, etc...
}
}

Related

Display a specific <div> content at setTimeout()

In the below code I am making an API call to my backend node.js app using setTimeout() which calls my AJAX at every 5 seconds. Inside my AJAX success I am displaying divContent1 & divContent2 based on certain condition which should execute at least once. After that only divContent2 should be visible at each setTimeout() calls.
index.html
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
url: "http://localhost:8070/api/route1",
type: 'POST',
dataType:'json',
success: function(res) {
//Some Task
}
});
$("#myButton").click(function(){
const route2 = function() {
$.ajax({
url: "http://localhost:8070/api/route2",
type: "POST",
dataType: "json",
data: { var1: val1 },
success: function (res) {
// Various tasks
if(res.flag){
$("#divContent1").hide();
$("#divContent2").show();
}
else{
$("#divContent1").show();
}
//Functions that handle div content data
},
beforeSend: function() {
$("#divContent1").hide();
$("#divContent2").hide();
},
complete: function() {
setTimeout(route2,5000);
},
});
};
$(function(){
route2();
})
});
});
</script>
The setTimeout() calls the entire route2 function which handles all the display and insertion of div content. However, the ask is to only display divContent2 from the second call.
Looking for a solution for this
The setTimeout() calls the entire route2 function which handles all
the display and insertion of div content. However, the ask is to only
display divContent2 from the second call.
You're calling route2 recursively with setTimeout(route2,5000); under complete. So this will run infinitely as complete occur each time an ajax call is completed (wether success or error). So what you can do is to create a timer and clear it after the second execution, something like this:
var ctr = 0, timer =0;
const route2 = function() {
$.ajax({
...
success: function (res) {
//Write you logic based on ctr
}
complete: function() {
if(ctr>0){
clearTimeout(timer)
}else{
timer = setTimeout(route2,5000);
ctr = ctr+ 1;
}
},
});
};
Will an external variable be enough? Just define it in the outer context and set/check it to choose the behavior:
// before declaring button click handler
var requestDoneAtLeastOnce = false;
// ...
// somewhere in success handler
success: function (res) {
if (!requestDoneAtLeastOnce) {
requestDoneAtLeastOnce = true;
// do something that belongs only to handling the first response
}
else {
// this is at least the second request, the other set of commands belongs here
}
}

javascript update modal form element whilst the ui is blocked due to code execution

ok, I have seen many, many articles about this. But so far I have not got any to work. So this is my take on the issue.
I have a list of employee names with ids held in a select option, and a button that when clicked, calls a routine for each option in the select
$(document).on("click", ".js-button-update-all-drivers", function (e) {
e.preventDefault();
myApplication.busy(true);
$("#modalInfo-body span").text("Starting update ...........");
$('.modalInfo-header .title').text("Information");
var modal = document.getElementById('modalInfo');
myApplication.openModal(modal);
var selected = document.getElementsByClassName('js-dropdown-selector');
for (var i = 0; i < selected[0].options.length; i++) {
var Id = selected[0].options[i].value;
$("#modalInfo-body span").text("Updating - " + Id);
doWork(Id);
}
myApplication.closeModal(modal);
myApplication.busy(false);
});
This calls a function call doWork which is defined as async/wait
async function doWork(employeeId, taxWeek, taxYear) {
try {
const response = await processUpdate(Id);
} catch (err) {
$("#modalInfo-body span").text("Report Error - Thank you.");
}
}
Which in turn calls the following function:
function processUpdate(Id) {
return new Promise((resolve, reject) => {
$.ajax({
url: '/myTest',
async: false,
data: {
Id: Id
},
method: 'post',
dataType: 'json',
success: function(retData) {
if (retData === false) {
resolve('Completed');
} else {
reject('An error has occurred, please send a screen shot');
}
},
error: function(xhr, error) {
reject('An error has occurred, please send a screen shot'); }
});
});
}
Although this code works, the element $("#modalInfo-body span") is not updated as it loops around the doWork function.
I already have a spinner on the screen, but am looking for a more visual aid to how this is progressing.
OK, I am going to start this by saying that I knew the browser is single threaded, and this was not going to be easy.
I did try callbacks and that did not work completely, as I encountered a delay in updating the screen.
So ultimately, I replaced this with a simple spinner.
Thanks to all that took the timer to look at this.

Call ajax on before page unload

I'm trying to call an ajax before user leaving a page, this what i have done so far. But it doesn't even hit the ajax page.
This is what i have done so far.
window.onbeforeunload = closeIt();
function closeIt()
{
var key="save-draft";
$.ajax({
url: "app/ajax_handler.php",
type:"GET",
data:{key:key},
success: function(data) {
return data;
}
});
}
I Have tried this one also both failed in my case.
$( window ).unload(function() {});
The only way I think is to let the user know that it's a process on background with a confirm message, that will block the exit until user click on Accept or you've got the response.
Something like that:
window.onbeforeunload = closeIt();
function closeIt()
{
/*var key="save-draft";
$.ajax({
url: "app/ajax_handler.php",
type:"GET",
data:{key:key},
success: function(data) {
return data;
}
});*/
setTimeout(function() {
return confirm("There is a process that isn't finished yet, you will lose some data. Are you sure you want to exit?");
}, 1000);
}

Javascript- How to check if operation has been completed on this event

Is there any way to check if the event is completed and element is free to perform another action?
Like I want to do
$('#button-cancel').on('click', function() {
// send ajax call
});
/****************************************
extra code
*******************************************/
$('#button-cancel').on('click', function() {
if(ajax call is completed) {
//do some thing
}
});
I don't want to send ajax call in second onclick as it is already been sent, just want to check if it is done with ajax then do this
You can introduce a helper variable:
// introduce variable
var wasAjaxRun = false;
$('#button-cancel').on('click', function() {
// in ajax complete event you change the value of variable:
$.ajax({
url: "yoururl"
// other parameters
}).done(function() {
// your other handling logic
wasAjaxRun = true;
});
});
$('#button-cancel').on('click', function() {
if(wasAjaxRun === true) {
//do some thing
}
});
EDIT: I just noticed that you have event handlers attached to the same button. In that case my initial answer would not work, because first event hander would be executed every time you click the button.
It is not very clear from the description what you want to do with your first event hander. I assume you want to use some data, and if you already have this data, then you use it immediately (like in second handler), if you don't have it - you make the AJAX call to get the data (like in first handler).
For such scenario you could use single event handler with some conditions:
var isAjaxRunning = false; // true only if AJAX call is in progress
var dataYouNeed; // stores the data that you need
$('#button-cancel').on('click', function() {
if(isAjaxRunning){
return; // if AJAX is in progress there is nothing we can do
}
// check if you already have the data, this assumes you data cannot be falsey
if(dataYouNeed){
// You already have the data
// perform the logic you had in your second event handler
}
else { // no data, you need to get it using AJAX
isAjaxRunning = true; // set the flag to prevent multiple AJAX calls
$.ajax({
url: "yoururl"
}).done(function(result) {
dataYouNeed = result;
}).always(function(){
isAjaxRunning = false;
});
}
});
You should be able to provide handlers for AJAX return codes. e.g
$.ajax({
type: "post", url: "/SomeController/SomeAction",
success: function (data, text) {
//...
},
error: function (request, status, error) {
alert(request.responseText);
}
});
you can disable the button as soon as it enters in to the event and enable it back in ajax success or error method
$('#button-cancel').on('click', function() {
// Disable button
if(ajax call is completed) {
//do some thing
//enable it back
}
});
This is edited, more complete version of dotnetums's answer, which looks like will only work once..
// introduce variable
var ajaxIsRunning = false;
$('#button').on('click', function() {
// check state of variable, if running quit.
if(ajaxIsRunning) return al("please wait, ajax is running..");
// Else mark it to true
ajaxIsRunning = true;
// in ajax complete event you change the value of variable:
$.ajax({
url: "yoururl"
}).done(function() {
// Set it back to false so the button can be used again
ajaxIsRunning = false;
});
});
You just need to set a flag that indicates ajax call is underway, then clear it when ajax call returns.
var ajaxProcessing = false;
$('#button-cancel').on('click', function(){
processAjaxCall();
});
function processAjaxCall() {
if(ajaxProcessing) return;
ajaxProcessing = true; //set the flag
$.ajax({
url: 'http://stackoverflow.com/questions/36506931/javascript-how-to-check-if-operation-has-been-completed-on-this-event'
})
.done(function(resp){
//do something
alert('success');
})
.fail(function(){
//handle error
alert('error');
})
.always(function(){
ajaxprocessing = false; //clear the flag
})
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button-cancel">Cancel</button>
What you can do is call a function at the end of an if statement like
if(ajax call is completed) {
checkDone();
}
function checkDone() {
alert("Done");
}

Why does my JQuery AJAX call execute twice, but only if it's not called first?

On my portfolio website, I am using a jQuery .ajax() call to pull in my portfolio pieces via XML.
My issue is that after a fresh page load, if the "portfolio" link is clicked first, then the portfolio pieces are pulled in normally. If, after a fresh page load, the "portfolio" link is clicked after any of the other links, then the portfolio pieces are pulled in twice.
You can see the issue for yourself on my site: Transhuman Creative
Here is the code that figures out which navigation link is clicked based on its rel attribute:
$("#nav a").click( function () {
if($(this).attr("rel") == "blog") {
return false;
}else{
$("#nav a").removeClass("selected");
$(this).addClass("selected");
setBlock($(this).attr("rel"));
}
});
After a link is clicked, it is processed by theThe setBlock() function, which hides existing content and calls the processBlock() function to load content.
function setBlock(block) {
if(firstNav) {
processBlock(block);
firstNav = false;
}
else
{
if($(".tab").length > 0 && $(".tab").is(":hidden") == false) {
$(".hidable").fadeOut();
$(".tab").fadeOut(function(){
processBlock(block);
});
}
else {
$(".hidable").fadeOut(function (){
processBlock(block);
});
}
}
}
The processBlock() function waits 500ms to let the animation finish, then either shows the block of content or calls the loadItems() function to load the portfolio data.
function processBlock(block) {
var s = setInterval( function () {
if (block == "portfolio") {
loadItems();
}else{
$("." + block).fadeIn();
}
clearInterval(s);
}, 500);
}
And finally, the .ajax() call is in the loadItems() function. After loading the porfolio data from the XML file, it calls the tabFade() function to parse the data and generate the HTML for the portfolio pieces. The variable firstCall is initially set to true, and it is meant to prevent the portfolio data from being reloaded if it's already in memory:
function loadItems() {
if (firstCall) {
$.ajax({
type: "GET",
url: "data/portfolio.xml?ver=1.11",
cache: false,
dataType: "xml",
success: function(xml){
$(xml).find('item').each(function(){
$("#main").append(addItem($(this)));
});
tabFade();
firstCall = false;
}
});
}else{
tabFade();
}
}
Any thoughts on what might be causing the double load issue? Thanks for your help.
I believe it would be better to set the firstCall variable right inside of the if condition. Otherwise it waits 500+ milliseconds before being set and only gets set once the ajax request completes.
function loadItems() {
if (firstCall) {
firstCall = false; // Put the assignment here before waiting.
$.ajax({
type: "GET",
url: "data/portfolio.xml?ver=1.11",
cache: false,
dataType: "xml",
success: function(xml){
$(xml).find('item').each(function(){
$("#main").append(addItem($(this)));
});
tabFade();
//firstCall = false;
}
});
}else{
tabFade();
}
}
Try using setTimeout instead of setInterval. You probably want to use setTimeout anyway as I don't think you want to run the code more than once?
It could be that it's running that code twice and making two ajax calls as it hasn't responded within 500ms.

Categories