I want to check internet connection with a test, with jquery
my js:
/* detect connexion */
function detectConnexionTest() {
var urlOnline = "/connect";
jQuery.ajax({
type: 'POST',
url: urlOnline,
success: function(data, textStatus, xhr) {
console.log(xhr.status);
detectConnexion("yes");
},
error: function(xhr, textStatus, errorThrown) {
console.log(xhr.status);
detectConnexion("no");
}
});
}
function detectConnexion(value) {
if (value == "yes") {
return true;
} else if (value == "no") {
return false;
} else {
return false;
}
}
and after, the calling in a angularjs controller :
detectConnexionTest();
if (detectConnexion() === true) {
$scope.online = "connected";
} else if (detectConnexion() === false) {
$scope.online = "not connected";
}
html :
<p>are you connected ? : {{online}}</p>
i'm confused about call the testing function detectConnexionTest , and my scope show me always "not connected" even if i'm connected and get "200" status... what's wrong ?
You call detectConnexionTest() which begins an AJAX request and returns immediately
You call detectConnexion() with no parameter immediatly afterwards, which is guaranteed to return false even if your AJAX request had completed
When your AJAX call does return, you call detectConnexion() and do pass a value and it will return true or false, but you don't store that return value.
Since you're using jQuery.ajax(), angular does not know when your call returns so even if you did update a value on your scope properly your page would not update until angular went through another digest cycle.
What you should probably do is use $http and set the scope value when the call returns:
function TestCtrl($scope, $http) {
function detectConnexion() {
$http.post("/connect").success(function(data, status, headers, config) {
$scope.online = "connected";
}).error(function(data, status, headers, config) {
$scope.online = "not connected";
}
}
detectConnexion();
}
You're getting it wrong, try to understand how AJAX works, this is one way to do it pretty similar to what you've got there:
Change the detectConnexion function to this:
function detectConnexion(value) {
if (value == "yes") {
connected = true;
} else if (value == "no") {
connected = false;
} else {
connected = false;
}
}
And change the code in the angular controller to this:
detectConnexionTest();
if (connected === true) {
$scope.online = "connected";
} else if (connected === false) {
$scope.online = "not connected";
}
Try the following code, it's cleaned a bit.
function detectConnexionTest() {
var urlOnline = "/connect";
jQuery.ajax({
type: 'GET',
url: urlOnline,
success: function(data, textStatus, xhr) {
detectConnexion(true);
},
error: function(xhr, textStatus, errorThrown) {
detectConnexion(false);
}
});
}
function detectConnexion(b) {
$scope.online = b ? "connected" : "not connected";
}
detectConnexionTest();
By far the easiest way to do this is with the navigator.onLine property. You could implement the javascript to run when a button is pressed. You can put it into a simple if, else statement. Read more here:
http://www.w3schools.com/jsref/prop_nav_online.asp
Example:
function checkConnection() {
if (navigator.onLine) {
// Action
} else {
// Action
}
}
Related
I'm uploading a list of documents to the server, and for each document I launch an ajax request, but the number of requests is unknown (Depends on the number of document being uploaded). How can I show a message to the user when all the documents are uploaded (All ajax requests are done).
$.each(files,function(idx,elm){
let formData = new FormData();
let ID = '_' + Math.random().toString(36).substr(2, 9);
formData.append('document_id', ID);
formData.append('file-doc', elm);
$.ajax({
url: "http://127.0.0.1:5000/add_multiple_docs",
type: 'POST',
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
},
success: function (data) {
alert(data);
},
failure: function (request) {
console.log(request);
},
error: function (jqXHR, exception) {
console.log("error add document");
let msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status === 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status === 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
console.log(msg)
}
});
});
}
First of all, you know how many files are uploaded, so you know how many ajax request you are doing. (1 Request per file)
So before your $.each() fires you get the size of files
let count = $(files).size();
$.each(files,function(idx,elm){
/*your code with requests*/
}
Now, after each ajax request hast fired, decrement count. Decrement inside your success and failure methods, because it doesn't mattet if it succeeded or not. And check if count === 0. If it's 0 than you know all ajax are done.
$.ajax({
/*your other settings*/
success: function (data) {
alert(data);
count--;
doSomething(count);
},
failure: function (request) {
console.log(request);
count--;
doSomething(count);
},
});
function doSomething(count){
if(count === 0){
/*stuff you wannna do after all ajax requests are done*/
}
}
I haven't done that many ajax for now, so I'm not quite sure if failure is also fired on error, but if not maybe add count-- and the if on error as well.
To achieve what you need you can place all the jqXHR objects returned from $.ajax() in an array which you can apply() to $.when(). Then you can execute whatever logic you require after all of those promises have been resolved. Try this:
var promises = files.map(function(elm) {
// setup formData...
return $.ajax({
url: "http://127.0.0.1:5000/add_multiple_docs",
// ajax settings...
});
});
$.when.apply($, promises).done(function() {
console.log('all requests complete, do something here...');
});
However, it's definitely worth noting that sending AJAX requests in a loop is not a scalable pattern to use. It would be a much better idea to aggregate all the file and related data in a single AJAX request and handle that once on the server.
A very interesting question.
I had a similar issue when trying to get data from the youtube API which only returned a max result set of 50 items.
To solve this problem I used a recursive function that accepted a callback, on base case (in my case when there was no nextPageToken) I called the callback function.
The recursion was triggered in the success handler of the $.ajax request.
function fetchVideos(nextPageToken, callback) {
if (nextPageToken === null || nextPageToken === undefined) {
callback(null);
return;
}
$.ajax(requestURI + `&pageToken=${nextPageToken}`, {
success: (data) => {
// use data somehow?
fetchVideos(data.nextPageToken, callback);
},
error: (err) => {
callback(err);
}
})
}
fetchVideos("", (err) => {
if (err) {
console.log(err.responseJSON);
return;
}
updateUI();
})
When there was no longer a nextPageToken in the response it would trigger the if statement. I think it works kind of sync? Because I need the nextPageToken to perform the next request.
I know this is not the best case for you situation, but I answered based on the title which is how I came to this page :)
I have a script which runs 2 AJAX calls, the first checks that a record exists within a database. If it does this should not move on and the script should stop. The second submits a job.
My problem is that the job is being submitted before the first AJAX call has returned. My code looks something like this:
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function( data ){
if (data.Response == "Success") {
var noresults = data.Results;
if (noresults > 0){
alert('this record id already exists!');
return false;
}
} else {
alert('an error occured');
return false;
}
}
});
} else {
alert('enter a record id');
return false;
}
// second ajax call goes here, which gets called regardless of the output of the ajax call above
Instead of putting the call to the second ajax method at the bottom of your code (where the comments currently are), put it in the "success" function of your first call. This method will only execute once the first call has finished. This is the only way to ensure that the second call does not happen too early. Ajax calls run asynchronously, so the normal flow of the browser is not interrupted. This is deliberate so that long-running calls don't lock up the browser for the user.
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function(data) {
//check here if you want to call submitJob or not
//and call submitJob()
}
});
} else {
alert('enter a record id');
return false;
}
//call this ajax once you varified your condition from success callback of first one
function submitJob() {
//second ajax call goes here
}
You have to use jquery promise function for that which will wait for the first ajax request to complete then make another ajax request.
JQUERY PROMISE
OR
Put the second ajax request in the success function of first one, and make it happen when you want it to fire
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function(data) {
//check here if you want to call submitJob or not
if (noresults > 0){ return false }
else { Job(); };
}
});
} else {
alert('enter a record id');
return false;
}
function Job() {
//another ajax call.
}
Hope it helps :)
try this: make async propety false
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
async : false, //added this
success: function( data ){
if (data.Response == "Success") {
var noresults = data.Results;
if (noresults > 0){
alert('this record id already exists!');
return false;
}
} else {
alert('an error occured');
return false;
}
}
});
} else {
alert('enter a record id');
return false;
}
OR
perform second ajax call in success function of first ajax call i.e. see comment
if (recordid) {
var request = $.ajax({
context: document.body,
url: URLGOESHERE,
data: {
recordID: recordid
},
success: function( data ){
if (data.Response == "Success") {
var noresults = data.Results;
if (noresults > 0){
alert('this record id already exists!');
return false;
}
//perform 2nd ajax call here
} else {
alert('an error occured');
return false;
}
}
});
} else {
alert('enter a record id');
return false;
}
Ok, what I am trying to do is alerting ajax errors according to its error codes and I have lots of ajax calls on website so I am using global ajax error handler function.
But what I want is if some ajax call already have default errors then show there not global.
$(document).ready(function(){
$(document).ajaxError(e,xhr,opt){
if(xhr.error){
//Don't do anything
} else {
alert('You have an error');
}
}
}
First Function :
$.ajax({
type:"post",
url:"page.php",
data:"name=mohit&lastname=bumb",
error:function(){
alert('error');
}
});
Second Function :
$.ajax({
type:"post",
url:"page.php",
data:"name=mohit&lastname=bumb",
});
So in 2nd case it should show You have an error and in first case just error
Yes you can, but you have to override jQuery default $.ajax methods. Check the following code that I used in one of my projects. Make sure you load the script just after jQuery.
My scenario was -
The web site had a lot of ajax partial views which had to check whether user is logged in or not. So I had to override jquery calls to check for it.
I also had to show a loader when any ajax call was made.
One more thing, some js are loaded by ajax, so I added a check whether the url is a .js file or normal url.
I have taken out the sensitive codes that were confidential for my project. The rest is here. This might help you.
$(document).ready(function () {
var oldjQuery = [];
oldjQuery["ajax"] = $.ajax;
oldjQuery["load"] = $.load;
var newOptions = [];
//override ajax
jQuery.ajax = function (options) {
newOptions["ajax"] = $.extend({}, options);
//override the success callback
newOptions["ajax"].success = function (data, textStatus, jqXhr) {
try {
if (options.url.indexOf('.js') <= -1) {
//this is a normal success call, do nothing
}
}
catch (err) {
//... my other codes, incase any error occurred
}
if (typeof options.success != 'undefined') {
//the ajax call has a success method specified, so call it
options.success(data, textStatus, jqXhr);
}
};
//override the error callback
newOptions["ajax"].error = function (jqXhr, textStatus, errorThrown) {
try {
if (options.url.indexOf('.js') <= -1) {
//this is a normal success call, do nothing
}
}catch (y) {
//... my other codes, incase any error occurred
}
//the ajax call has an error method specified, so call it
if (typeof options.error != 'undefined') {
options.error(jqXhr, textStatus, errorThrown);
}
};
return oldjQuery["ajax"](newOptions["ajax"]);
};
//override load function
jQuery.load = function (url, data, completeCallback, ignore) {
newOptions["load"].completeCallback = function (d, textStatus, jqXhr) {
try {
if (url.indexOf('.js') <= -1) {
//codes
}
} catch (err) {
try {
//codes
}catch (err2) {
}
}
if (typeof completeCallback != 'undefined') {
//call the default completed callback
completeCallback(d, textStatus, jqXhr);
}
};
return oldjQuery["load"](url, data, newOptions["load"].completeCallback);
};
});
I'm using a prefilter to redo the ajax request 2 times max, see code below.
However the problem is that the original fail() handler of the ajax request is also called. This needs to be disabled of course.
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
// retry not set or less than 2 : retry not requested
if (!originalOptions.retryMax || !originalOptions.retryMax >= 2) {
return;
}
// no timeout was setup
if (!originalOptions.timeout > 0) {
return;
}
if (originalOptions.retryCount) {
originalOptions.retryCount++;
} else {
originalOptions.retryCount = 1;
// save the original error callback for later
if (originalOptions.error) {
originalOptions._error = originalOptions.error;
}
};
// overwrite *current request* error callback
options.error = $.noop();
// setup our own deferred object to also support promises that are only invoked
// once all of the retry attempts have been exhausted
var dfd = $.Deferred();
jqXHR.done(dfd.resolve);
// if the request fails, do something else yet still resolve
jqXHR.fail(function() {
var args = Array.prototype.slice.call(arguments);
if (originalOptions.retryCount >= originalOptions.retryMax || jqXHR.statusText !== "timeout") {
// add our _error callback to our promise object
if (originalOptions._error) {
dfd.fail(originalOptions._error);
}
dfd.rejectWith(jqXHR, args);
} else {
$.ajax(originalOptions).then(dfd.resolve, dfd.reject);
}
});
});
My request is: And i get the console.log message "we are in fail" at the same time as the request is redone for the first time. Any idea how to fix this?
$.ajax({
url: url,
crossDomain: true,
dataType: "json",
type: type,
timeout: 20000,
async: (async === undefined ? true : async),
beforeSend: beforeSend,
retryMax: (type == "POST" ? 0 : 2),
data: data
}).done(function(response, status, xhr) {
}).fail(function(xhr, textStatus, error) {
console.log("WE ARE IN FAIL");
});
easier way (sorry I only have the time to write partial code) :(
Create a recursive function that handle the ajax request and takes parameters + a counter.
var MyFuncAjax = function(params, counter){
if(counter <= 0){ return true; }
$ajax({
...
timeout: params.timeout
...
})
...fail(function(xhr...){
MyFuncAjax(params, --counter)
})
}
Then call it
MyFuncAjax({timeout: 20000, ....}, 2)
And voila :)
I have 3 ajax call in one function and checkAjaxCompletion which checks each ajax completion flag.
What the code below does is send multiple separate ajax calls and interval method checks completion flags to determine whether to proceed or keep interval. (I know clearInterval is not shown but the point is I want to use something other than interval)
Current code is:
function manyAjax() {
setInterval( function() { checkAjaxCompletion(); } , 200);
ajax1();
ajax2();
ajax3();
}
function ajax1() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax2() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function ajax3() {
//send ajax request to server and if success set flag to 1. Default is 0. Error is 2.
}
function checkAjaxCompletion() {
if(ajax1_flag == 1 && ajax2_flag == 1 && ajax3_flag == 1) {
//everything went success, do some process
}
else if(ajax1_flag == 2 || ajax2_flag == 2 || ajax3_flag == 2) {
//some ajax failed, do some process
}
else {
//all ajax have not been completed so keep interval i.e. do nothing here
}
}
But I'm hesitating to depend on using interval function because calling it so often seem such waste of memory. There must be better way to do. I'm thinking if observer pattern can be applied here but would like to hear opinions.
It is observer-notifier, if you want to call it that - but each of your ajax calls will more than likely have a callback in javascript when they complete. Why not call checkAjaxCompletion() at the end of each of them, and do nothing if you're still waiting on others?
Dustin Diaz does a great job with this example.
function Observer() {
this.fns = [];
}
Observer.prototype = {
subscribe : function(fn) {
this.fns.push(fn);
},
unsubscribe : function(fn) {
this.fns = this.fns.filter(
function(el) {
if ( el !== fn ) {
return el;
}
}
);
},
fire : function(o, thisObj) {
var scope = thisObj || window;
this.fns.forEach(
function(el) {
el.call(scope, o);
}
);
}
};
The publisher:
var o = new Observer;
o.fire('here is my data');
The subscriber:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
To unsubscribe:
var fn = function() {
// my callback stuff
};
o.subscribe(fn);
// ajax callback
this.ajaxCallback = function(){
$.ajax({
type: "POST",
url: ajax.url,
data: {key: value},
async : !isAll,// false使用同步方式执行AJAX,true使用异步方式执行ajax
dataType: "json",
success: function(data){
if(data.status == 'successful'){
selfVal.parent().find('.msg').addClass('ok').html(msg.ok);
}else if(data.status == 'failed'){
checkRet = false;
selfVal.parent().find('.msg').removeClass('ok').html(msg.error);
}else{
checkRet = false;
}
return this;
}
});
}
return this;
Maybe you want to check your inputvalue callback ajax in your form;
You can view my website Demo, hope help you.
http://6yang.net/myjavascriptlib/regForm
Okay my idea was to make your own object that can handle sending an array of requests, keep a history of each request and do what i'm gonna call 'postProccessing' on each response, here is a probably very dodgy bit of code to hopefully demonstrate what I am thinking.
var Ajax = function() {
var request, callback, lst;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
request.onreadystatechange = handleResponse;
this.history = [{}];
this.send = function(args) {
for (var i = 0; i < args.length; i++) {
if (args.url) {
request.open(args.type || 'GET', args.url);
}
request.send(args.data || null);
callback = args.callback;
lst++;
}
}
function handleResponse() {
var response = {
url: '',
success: true,
data: 'blah'
};
history.push(response);
if (postProccess()) {
callback();
}
}
function postProcess() {
if (this.history[lst].success) {
return true;
} else {
return false;
}
}
}