jquery when / then for recursive ajax calls - javascript

function getFriends(url) {
return FB.api(url, function(response) {
if (response && !response.error) {
if (response.paging && response.paging.next) {
$.each(response.data, function() {
friends.push(this);
});
return getFriends(response.paging.next);
} else {
console.error(friends);
}
} else {
console.error("facebook friends couldn't been retrieved ");
}
});
}
$.when(getFriends("/me/friends")).then(
function() {
console.log('getFriends finished');
});
i want to make sure that fb calls finished when the then() block executed but had no chance. is there a way to implement this ?
thanks

The Facebook JS SDK does not implement jQuery style promise objects / $.Deferreds but you can easily create an instance on your own like:
function getFriends(url) {
var dfd = $.Deferred();
FB.api(url, function(response) {
if (response && !response.error) {
if (response.paging && response.paging.next) {
$.each(response.data, function() {
friends.push(this);
});
return getFriends(response.paging.next);
} else {
console.log(friends);
}
dfd.resolve();
} else {
console.error("facebook friends couldn't been retrieved ");
dfd.reject();
}
});
return dfd;
}
getFriends("/me/friends").done(
function() {
console.log('getFriends finished');
}
);

Not really an answer, but a working example that demo's how to go about it:
Demo JSFiddle
function doStuff() {
var dfd = new jQuery.Deferred();
alert ("loaded");
setTimeout(function(){
dfd.resolve("response - success");
}, 5000);
return dfd.promise();
}
$.when(doStuff()).then(function(status) {
alert(status);
});

Related

Disable button until function is done

I am trying to disable the button until the code is successfully executed. Unfortunately, the button is activated too early, the function is still running. How can I prevent this?
$("#myButton").click(function() {
$(this).prop("disabled", true)
doSomethingFunction()
$(this).prop("disabled", false)
});
Edit:
Thank you all for your help. I have adjusted my code. Can you do it this way or are there better ways?
class TestClass
{
static doSomethingFunction() {
return new Promise(function (resolve, reject) {
setTimeout(function () { console.log("function is done"); resolve(self); }, 5000);
})
}
}
$("#myButton").click(function() {
$(this).prop("disabled", true)
TestClass.doSomethingFunction().then(r => $(this).prop("disabled", false))
});
The second solution does not work for me, because "completely done" is output before "function is done"
class TestClass
{
static doSomethingFunction(callback) {
setTimeout(function () { console.log("function is done");}, 2000);
if(callback !== undefined){
callback();
}
}
}
$("#myButton").click(function() {
$(this).prop("disabled", true)
TestClass.doSomethingFunction(function(){
console.log("completely done")
});
});
What am I doing wrong?
Consider the following.
var myData;
function doSomethingFunction(callback){
$.get("someplace.php", function(data){
myData = data;
if(callback !== undefined){
callback();
}
});
}
$("#myButton").click(function() {
var $self = $(this);
$self.prop("disabled", true);
doSomethingFunction(function(){
console.log(myData);
$self.prop("disabled", false);
});
});
This allows you to pass in code to run once the function is complete. In this example, maybe it's getting data from the server. This may take almost no time, or maybe the report takes 1.2 seconds to generate. Either way it will not be run until the AJAX is successful.
Update
Here is an example, based on the following: How do I use jQuery promise/deffered in a custom function?
$(function() {
function doSomething() {
var deferred = new $.Deferred();
setTimeout(function() {
deferred.resolve(10);
}, 10 * 1000);
return deferred;
}
$("button").click(function() {
var $self = $(this);
console.log("Disabled");
$self.prop("disabled", true);
doSomething().then(function() {
$self.prop("disabled", false);
console.log("Enabled");
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Start</button>
This will run for 10 seconds and then enable the button. Applying it to your example.
class TestClass {
static doSomethingFunction() {
var deferred = new $.Deferred();
setTimeout(function() {
deferred.resolve(10);
}, 5 * 1000);
return deferred;
}
}
$("#myButton").click(function() {
var $self = $(this);
$self.prop("disabled", true);
TestClass.doSomethingFunction().then(r => $self.prop("disabled", false));
});

Error in geolocation js (site.init is undefined)

I currently have a problem,
I have a client who wants his site in Argentina to be seen only in Argentina and that users entering from another country are redirected to the official website in France, and that when the API query is made if you are inside Argentina, the geolocation script is not executed It should be noted that the only way,the api that I am using is ip api, I have to create it in js. Because the system we are using does not give us access to server. and additionally a cookie must be saved. So I did the following.
var site = {
init: function() {
this.setDisplayClass();
this.global();
this.search();
this.newsletter();
menu.init();
minicart.amount(".cart-link .qty-items");
minicart.create();
minicart.hover();
if ($('body').hasClass('home')) {
banner.background('.main-banner-section .box-banner');
banner.slide('.run-slick');
shelf.slide('.featured-products-slider .shelf ul');
}
if ($('body').hasClass('grid-products')) {
grid.init();
}
if ($('body').hasClass('producto')) {
product.init();
shelf.slide('#related-products .shelf ul');
}
},
}
AND
var geo ={
init: function(){
var isAr = localStorage.getItem("country");
if((isAr == null) || (isAr == undefined)){
$.ajax({
url: 'http://ip-api.com/json/?callback=?',
async: false,
dataType: 'jsonp',
success: function (response) {
var country = response.countryCode;
if(country !== "AR"){
window.location.replace("https://www.google.com.ar");
}else{
localStorage.setItem('country', country);
if($(".loading-hidden").length > 0){
$(".loading-hidden").each(function(){
if ($(this).attr('style') == 'visibility: hidden;') {
console.log(1);
site.init();
$(this).removeAttr('style');
if ($("#loading").length > 0) {
$("#loading").remove();
}
}
});
}
}
}
});
}else{
if ($(".loading-hidden").attr('style') == 'visibility: hidden;') {
site.init();
$('.loading-hidden').removeAttr('style');
if ($("#loading").length > 0) {
$("#loading").remove();
}
}
}
}
}
AND
$(document).on('ready', function() {
});
site.init();
$(window).bind("load", function() {
});
The error I get is that site.init is undefined.

Accessing a function within a function inside object literals in javascript?

I have some code as follows -
var app = {
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
document.addEventListener('backbutton',this.receivedEvent.backbutton(),false);
^-- //not working
},
onDeviceReady: function() {
this.receivedEvent('deviceready');
},
receivedEvent: function(id) {
var originalLocation, partnership;
function fadeOut(element, direction) {
....
};
function fadeIn(element, direction) {
.....
}
function formFadeIn(direction) {
fadeIn($("#dataform"), direction);
};
function formFadeOut(direction) {
fadeOut($("#dataform"), direction);
};
function backbutton () {
var current = $("#home").attr("page-current");
var prev = $("#home").attr("page-prev");
if (current == "dataform" && prev == "partnertype") {
formFadeOut("opposite");
partnertypeFadeIn("opposite");
setPage("country", "partnertype")
$("#selectcountry").attr("disabled", false).val("AF")
} else if (current == "dataform" && prev == "country") {
formFadeOut("opposite");
countryFadeIn("opposite");
} else if (current == "partnertype" && prev == "country") {
partnertypeFadeOut("opposite");
countryFadeIn("opposite");
} else {
window.location.reload()
}
}
}
};
app.initialize();
So I need to bind the event "backbutton" to the function backbutton() within receivedEvent. function backbutton() is invoking local functions within receivedEvent such as formFadeIn() etc.
I am unable to figure out the exact syntax on binding.
What I've tried -
this.receivedEvent.backbutton //no response
this.receivedEvent.backbutton() //no response
this.receivedEvent.bind(this).backbutton //causes infinite looping on the page
exporting the backbutton() function as return { backbutton : backbutton } //no response
What do I have to do to access function backbutton() from app.initialize() without loosing context?
You could try :
var app = {
initialize: function() {
document.addEventListener('backbutton',this.myBackButtonFunction, false);
},
myBackButtonFunction: function() {
// Your code
}
receivedEvent: function(id) {
// Can also be invoked from here
this.myBackButtonFunction();
},
};
app.initialize();

ajax not working and chrome but working fine in IE

need help!!..it seems new Ajax.Request is not recognized based on the debug....
tried some of the recommendations online but not working..cache=false etc...
Thanks!
if (init) {
init = false;
param = "init=" + true;
param = encodeURI(param.replace(/^\s+|\s+$/g, ''));
setLastRequestTimestamp(); //ryan's trial
new Ajax.Request("downstocking_apply_async.do", {
onSuccess: function(transport) {
if (!isHangingRequest()) {
alert("initUpdateScanArea");
initUpdateScanArea(transport.responseText);
setLastRequestTimestamp();
} else {
if (signalOnScan() == 1) {
alert("<fmt:message key="
message.signal_scan_off " bundle="
$ {
application
}
"/>");
return;
}
alert("<fmt:message key="
message.signal_downstock_suspend " bundle="
$ {
application
}
"/>");
doSuspend();
}
},
onFailure: function(transport) {
if (!isHangingRequest()) {
document.downstockingForm.action = "downstocking_apply_async.do?" + param;
if (signalOnScan() == 1) {
alert("<fmt:message key="
message.signal_scan_off " bundle="
$ {
application
}
"/>");
return;
}
setLastRequestTimestamp();
document.downstockingForm.submit();
} else {
if (signalOnScan() == 1) {
alert("message");
return;
}
alert("message");
doSuspend();
}
},
parameters: param,
asynchronous: "true"
});
}
found the solution...a custom js library that was imported is creating confusion with prototype js
Removed the custom library and it works now... thanks!

Jquery Trigger event when JSON .each is done

I have the following code to ping a list of computers with Jquery and asp.net.
function ping() {
$('#progress').css("display", "");
$('.comp').each(function () {
var $computer = $(this);
$.getJSON('pingcomputer.aspx', { computer: $(this).attr("rel") }, function (data) {
if (data.Status == '1') {
$($computer).attr("src", "ok.png");
}
else {
$($computer).attr("src", "nok.png");
}
})
})
$('#progress').css("display", "none");
}
The pinging works fine.
Before the ping start I want to make #progress visible (an image)
After all computers are pinged I want to hide it again.
The problem is that the #progress image is immediately hidden when the function is called.
How can I detect when all "pingcomputer.aspx" pages have finished loading?
Add a counter which checks that as many requests have been completed as there was started:
function ping() {
$('#progress').css("display", "");
var count = 0,
total = $(".comp").length;
$('.comp').each(function () {
var $computer = $(this);
$.getJSON('pingcomputer.aspx', { computer: $(this).attr("rel") }, function (data) {
count++;
if (data.Status == '1') {
$($computer).attr("src", "ok.png");
}
else {
$($computer).attr("src", "nok.png");
}
if (count==total) $('#progress').css("display", "none");
})
})
}
Count the number of things that should happen, decrement the count each time one thing does. When there are none left, stop the progress bar. BTW, any reason you're not using show()/hide()?
function ping() {
$('#progress').show();
var $comp = $('.comp'),
waitCount = $(comp).length;
$comp.each(function () {
var $computer = $(this);
$.getJSON('pingcomputer.aspx', { computer: $(this).attr("rel") }, function (data) {
if (data.Status == '1') {
$($computer).attr("src", "ok.png");
}
else {
$($computer).attr("src", "nok.png");
}
if (--waitCount == 0) {
$('#progress').hide();
}
})
})
}

Categories