How do I rewrite this function to be asynchronous? [duplicate] - ajax

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I have a function that pulls images from an API to insert them in an animated scroller. It looks like this (simplified for clarity):
function getPhotos(id) {
$.when(Service.getPhotos(id))
.then(function(results) {
var photos = results.photos,
scroller = $("#scroller");
// Add the photos to the scroller
for (var i = 0; i < photos.length; i++) {
var photo = photos[i].url;
// Only add a photo if its URL is valid
if (photoExists(photo) == 200) {
scroller.append("<li><img src='" + photo + "' /></li>");
} else {
console.log("Photo " + photo + " doesn't exist");
}
}
})
.fail(function(err) {
console.log(err);
});
}
However, the photo URLs don't always resolve to valid images, so I run them through the photoExists() function:
function photoExists(photo) {
var http = jQuery.ajax({
type: "HEAD",
url: photo,
async: false
});
return http.status;
}
If a given photo URL returns a status code of 200, then I know the image exists and I insert it into the scroller; otherwise, I skip over it so that I don't insert a broken image.
The problem here is that async: false – because this isn't asynchronous, the whole UI locks up until everything completes, which can be a very long time depending on how many photo URLs I have to loop through.
If I use async: true, however, then the photoExists() function attempts to return the status code before the AJAX request itself actually completes – so photoExists(photo) never returns 200, resulting in nothing being added to the scroller.
How would I adjust this so that photoExists() can run asynchronously and therefore avoid locking up the UI, but still return the correct status code so I can insert the photos into the scroller properly?

You need to provide a callback function for your photoExists function. Something like this:
function photoExists(photo, callback) {
var http = jQuery.ajax({
type: "HEAD",
url: photo,
async: true,
success: function(){
callback(photo, true);
},
error: function(){
callback(photo, false);
}
});
}
Then use it like so:
for (var i = 0; i < photos.length; i++) {
var photo = photos[i].url;
// Only add a photo if its URL is valid
photoExists(photo, function(photo, isSuccessful){
if (isSuccessful) {
scroller.append("<li><img src='" + photo + "' /></li>");
} else {
console.log("Photo " + photo + " doesn't exist");
}
});
}
Added photo to callback function to avoid possible closure issues with the for loop

Related

admin-ajax.php do not recognizes 'action'. $_REQUEST is empty

After two days of fruitless research, I decided to join the community. I hope to get a solution. I develop a plug-in that, among other things, must implement the upload of documents. this should be done using ajax technology. the problem is that the request is approved, but admin_ajax.php reacts like no action was taken. Outside of wp this piece of code works fine, as it was thought out. The problems come with installing this code in wp. Below is my code
PHP. This code in the main class that will call from main modul of plugin
class main{
//other activation methods
private function register_scripts(){
add_action('wp_enqueue_scripts', array($this,'re_add_script'));
}
public function re_add_script() {
wp_enqueue_script('re_upload',plugins_url('re'.'/js/re_upload.js'),array('jquery'));
wp_localize_script('re_upload',"re_ajax",array(
'ajaxurl'=>admin_url("admin-ajax.php")));
add_action( 'wp_ajax_upload', 'processingUpload');
}
}//end of class
//callback function
function processingUpload(){
$clsUpload = new UploadsDocs();
$clsUpload->setRequestedData($_FILES,$_POST['doc_id']);
$clsUpload->checkUploadsFiles();
$clsUpload->outputFilesList();
wp_die();
}
jQuery 're_upload.js'
jQuery(document).ready(function (e) {
jQuery('#bt_upload').on('click', function () {
var toUpload=getFileListToUpload();
var form_data = new FormData();
var ins = input.files.length;
for (var x = 0; x < ins; x++) {
if (isFileToUpload(input.files[x],toUpload)){
form_data.append("files[]", input.files[x]);
}
}
form_data.append("doc_id", jQuery('#doc_id')[0].value);
var data_to_sent={
action: 'upload',
datas: form_data
};
jQuery.ajax({
url: re_ajax.ajaxurl, // point to server-side PHP script
dataType: 'text', // what to expect back from the PHP script
cache: false,
contentType: false,
processData: false,
data: data_to_sent,
type: 'post',
success: function (response) {
// do something
},
error: function (response) {
// do something
},
xhr: function(){
//upload Progress
var xhr = jQuery.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position;
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
}
//update progressbar
jQuery('#bt_upload').css("display","none");
jQuery('#progress-wrp').css("display","block");
jQuery('#progress-wrp' +" .progress-bar").css("width", + percent +"%");
(percent<50)? jQuery('#progress-status').addClass('status-less-then-50'): jQuery('.status-less-then-50').removeClass('status-less-then-50').addClass('status-more-then-50');
jQuery('#progress-status').text("Uploading..."+percent +"%");
}, true);
}
return xhr;
},
mimeType:"multipart/form-data"
});
});
});
function getFileListToUpload(){
var list=[];
var elem = document.getElementsByClassName('preview');
var tag_li=elem[0].querySelectorAll('p');
for (var i=0;i<tag_li.length;i++){
list[i]=tag_li[i].textContent.split('(')[0];
}
return list;
}
function isFileToUpload(input_file,files_toUpload){
var res=false;
for(var i=0; i<files_toUpload.length;i++){
if (input_file.name==files_toUpload[i]){
res=true;
break;
}
}
return res;
}
The problem is
add_action( 'wp_ajax_upload', 'processingUpload');
is not called.
The upload is done in two separate invocations of the server. The first invocation displays the upload page to the user. The second invocation processes the AJAX request. Your call to
add_action( 'wp_ajax_upload', 'processingUpload');
is done in the first invocation where it is not needed but not in the second invocation where it is needed.
Please read https://codex.wordpress.org/AJAX_in_Plugins. (Observe carefully how the call to 'add_action( 'wp_ajax_...', ...) is done.) Further, you need to read about nonces.
Try to append action to your ajax url like:
url: re_ajax.ajaxurl?action=upload
and
data: form_data
or pass it to form_data like:
form_data.append('action', 'upload')

jQuery.ajax() inside a loop [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
If I call jQuery.ajax() inside a loop, would it cause the call in current iteration overwrite the last call or a new XHR object is assigned for the new request?
I have a loop that do this, while from console log I can see requests done 200 ok but just the result data of the last request in the loop is stored by the request success callback as supposed .
the code:
var Ajax = {
pages: {},
current_request: null,
prefetch: function () {
currentPath = location.pathname.substr(1);
if(this.pages[currentPath])
{
var current = this.pages[currentPath];
delete this.pages[currentPath];
current['name']=currentPath;
current['title']=$("title").text().replace(' - '.SITE_NAME, '');
current['meta_description']=$("meta[name=description]").attr('content');
current['meta_keywords']=$("meta[name=keywords]").attr('content');
}
var _Ajax = this;
//the loop in question *****
for(var key in this.pages)
{
$.ajax({
method: 'get',
url:'http://'+location.hostname+'/'+key,
success: function(data) {
_Ajax.pages[key] = data;
}
});
console.debug(this.pages);
}
if(current)
{
this.pages[currentPath] = current;
}
}
};//Ajax Obj
for(var i in pages)
{
Ajax.pages[pages[i]]={};
}
$(function() {
Ajax.prefetch();
});//doc ready
You'll need a closure for key:
for(var k in this.pages){
(function(key){
$.ajax({
method: 'get',
url:'http://'+location.hostname+'/'+key,
success: function(data) {
_Ajax.pages[key] = data;
}
});
console.debug(this.pages);
})(k);
}
that way you make sure that key is always the correct on in each ajax success callback.
but other than that it should work
i made a small closure demonstration using timeout instead of ajax but the principle is the same:
http://jsfiddle.net/KS6q5/
You need to use async:false in you ajax request. It will send the ajax request synchronously waiting for the previous request to finish and then sending the next request.
$.ajax({
type: 'POST',
url: 'http://stackoverflow.com',
data: data,
async: false,
success: function(data) {
//do something
},
error: function(jqXHR) {
//do something
}
});
I believe what's happening here has to do with closure. In this loop:
for(var key in this.pages)
{
$.ajax({
method: 'get',
url:'http://'+location.hostname+'/'+key,
success: function(data) {
_Ajax.pages[key] = data;
}
});
console.debug(this.pages);
}
The variable key is actually defined outside the for loop. So by the time you get to the callbacks, the value has probably changed. Try something like this instead:
http://jsfiddle.net/VHWvs/
var pages = ["a", "b", "c"];
for (var key in pages) {
console.log('before: ' + key);
(function (thisKey) {
setTimeout(function () {
console.log('after: ' + thisKey);
}, 1000);
})(key);
}
I was facing the same situation, I solved using the ajax call inside a new function then invoke the function into the loop.
It would looks like:
function a(){
for(var key in this.pages)
{
var paramsOut [] = ...
myAjaxCall(key,paramsOut);
.......
}
}
function myAjaxCall(paramsIn,paramsOut)
{
$.ajax({
method: 'get',
url:'http://'+location.hostname+'/'+paramsIn[0],
success: function(data) {
paramsOut[key] = data;
}
});
}
This is how I always do a ajax loop..
I use a recursive function that gets called after the xhr.readyState == 4
i = 0
process()
function process() {
if (i < 10) {
url = "http://some.." + i
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
alert(xhr.responseText)
i++
process()
}
}
xhr.send();
} else {
alert("done")
}
}

MVC ajax testing form submission

I am trying to submit a form using ajax and want to check to see if the
correct values are sent. How do I do it using the following. Currently, it is sending it to a MVC controller, but I do not want to do that. Is there a way to just sent to the same view page and show all the values???
$(document).ready(function () {
$("#btnSubmit").click(sendValues);
});
function sendValues() {
var a = store.data.items;
var array = new Array();
for (var i = 0; i < store.data.items.length; i++) {
array[i] = store.data.items[i].data;
}
for (var i = 0; i < array.length; i++) {
if (array[i].value == "Using") {
array[i].value = true;
}
else {
array[i].value = false;
}
}
var ClintJSON =
{
"Exempt": Ext.getCmp("mmrComboBox").isIndexSelected(2),
"MM1": Ext.getCmp("mmrComboBox").isIndexSelected(3),
"MM2": Ext.getCmp("mmrComboBox").isIndexSelected(4),
"MM3": Ext.getCmp("mmrComboBox").isIndexSelected(5),
"B1": Ext.getCmp("BComboBox").isIndexSelected(2),
"B2": Ext.getCmp("BComboBox").isIndexSelected(3),
"B3": Ext.getCmp("BComboBox").isIndexSelected(4)
};
$.ajax({
jsonp: null,
jsonpCallback: null,
type: 'POST',
url: '#Url.Content("~/Site/Test")',
data: "{clinsite: " + Ext.util.JSON.encode(ClintJSON) + ", List: " + `
Ext.util.JSON.encode(array) + "}",
dataType: 'json'
, contentType: 'application/json; charset=utf-8'
, success: function (data) {
if (data.success) {
showMessage('Site requirements have been updated successfully');
store.load({ params: { start: 0, limit: 52} });
} else {
showMessage('Site requirements have NOT been updated!!! ');
store.load({ params: { start: 0, limit: 50} });
}
}
});
There is one tool that I cannot recommend enough in this type of scenario, Fiddler2.
You can download it here
It enabled you to examine exactly what is passed to and from the server and you can view the data in various formats i.e. json, web form data or plain old text.
You can also use Composer to simulate http requests, which has its obvious benefits.
As a profession web applications developer, I use this tool all day every day, like I said I can't recommend it enough!!
Cheers
Baz
you can inspect the values in firefox using firebug console or in chrome tools, just press f12 and a window will open infront of your
moreover you can log the ClientJaon to the console liek
console.log(ClintJSON );

$(document).ajaxstart not firing

I have two functions that make $.getJSON calls - one looks at JSON stored on server, and the other one makes a call to Flickr.
I have this:
$(document).ajaxStart(function(){
alert('requeststart');
//$('#loading').show();
});
which works when $.getJSON is called with some given path, but it does not raise an alert when $.getJSON makes the call to Flickr. The Flickr call works, and everything loads as it should... it doesn't fire ajaxStart however. (I'm using ajaxStart and ajaxStop to show a loading-gif)
Any ideas?
Here is the function that calls Flickr :
$('#submit').on("click", function (evt) {
evt.preventDefault();
var tag = $('input').val();
if (tag == "") {
alert("please enter a tag");
}
else {
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?",{tags: tag, tagmode: "any", format: "json" },
function(data) {
$.each(data.items, function(i,item){
var name = names[index];
$("#" + name).empty();
$('<img src="' + item.media.m.replace("_m.jpg", ".jpg") + '" />').appendTo("#" + name);
$(' ' + item.title + '').appendTo("#" + name );
index ++;
if (i==5) {
index = 0;
}
});
});
}
});
jQuery only fires those events (ajaxStart and ajaxStop) if it internally uses the XMLHttpRequest object.
However if you request data from a different domain using a callback parameter (JSONP), jQuery does not use XMLHttpRequest, instead it accomplishes that by inserting a <script> tag.
That's why the events get not fired.
As a workaround you could start your loading animation just before the $.getJSON call, and stop it inside the function(data) {.. block.
for multiply requests you have too count them individually. I did it like this:
var loader = 0;
function showloader(cnt){
loader = loader + cnt;
if(loader < 1) {
$('#loading').hide();
} else {
$('#loading').show();
}
}
increase by 1 and call it before $.getJSON and decrease it and fire again when its done. like:
showloader(1);
$.getJSON(
[...]
}).done(function() {
showloader(-1);
[...]
});

Kill an ajax process

GET_DATA()
GET_DATA() contains this:
var xhr;
...
function get_data( phrase ) {
xhr = function get_data( phrase ) {
$.ajax({
type: 'POST',
url: 'http://intranet/webservice.asmx/GetData',
data: '{phrase: "' + phrase + '"}',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function( results ) {
$("#div1").empty();
if( results.d[0] ) {
$.each( results.d, function( index, data ) {
$("#div1").append( data.Group + ':' + data.Count + '<br />' );
});
} else {
alert( "results.d does not exist..." );
}
},
error: function(xhr, status, error) {
$('#spanLoading').empty();
var err = eval("(" + xhr.responseText + ")");
alert(err.Message) ;
}
});
}
function get_default() {
$('#div1').empty().append("default stuff goes here");
}
UPDATE 2 CODE
I've also tried this, which doesn't work either, no error messages, just returns the results of when the textbox had 2 characters when it finishes processing even if I delete everything before the process has finished:
$('#TextBox1').keyup( function() {
if(xhr && xhr.readystate != 4){
xhr.abort();
}
if ($("#TextBox1").val().length >= 2) {
get_data( $("#TextBox1").val() );
} else {
get_default();
}
});
UPDATE 1 CODE:
$('#TextBox1').keyup( function() {
if ($("#TextBox1").val().length >= 2) {
get_data( $("#TextBox1").val() );
} else {
if(xhr)
{
xhr.abort();
}
get_default();
}
});
ORIGINAL QUESTION:
I have the following code:
$('#TextBox1').keyup( function() {
if ($("#TextBox1").val().length >= 2) {
get_data( $("#TextBox1").val() );
} else {
get_default();
}
});
This has a slight glitch where if I type something really fast and then I delete it equaly fast, I see the data from get_default() flash on the screen, then it gets replaced by a previous ajax request where the value in the textbox was 2 which had not finished processing.
So basically, what I think is happening is that when the textbox has 2 characters in it, the ajax request starts which takes a second or 2. While this is happening, if I delete the 2 characters, I see the get_default() being successful, but it seems to replace it with the ajax data when the ajax data finishes.
How do I stop this from happening?
Thank you for posting get_data.
The reason why your AJAX call is not getting aborted is that xhr is not defined in the appropriate (window) scope; therefor, xhr.abort() doesn't do anything (and quite probably throws an error if you take a look at your console).
Please try the following:
var xhr = false;
function get_data( phrase ) {
xhr = $.ajax({ /* ... etc */
}
The rest should work as is.
Place a time delay before you execute your ajax request.
function pausecomp(ms) {
ms += new Date().getTime();
while (new Date() < ms){}
}

Resources