How could I trigger func when another has been completed? - javascript

I am using JQuery to collect latest tweets using Twitter API, but I am having some issues when calling two functions.
$(document).ready(function(){
JQTWEET.loadTweets();
});
This, is working ok, but then I want to call this function:
showHideTweets: function() {
alert("hola");
var ojeto = $(JQTWEET.appendTo).find(".item").first();
$(JQTWEET.appendTo).find(".item").first().css("display", "block");
},
Both functions are inside: jqtweet.js ...
loadTweets: function() {
var request;
// different JSON request {hash|user}
if (JQTWEET.search) {
request = {
q: JQTWEET.search,
count: JQTWEET.numTweets,
api: 'search_tweets'
}
} else {
request = {
q: JQTWEET.user,
count: JQTWEET.numTweets,
api: 'statuses_userTimeline'
}
}
$.ajax({
url: 'tweets.php',
type: 'POST',
dataType: 'json',
data: request,
success: function(data, textStatus, xhr) {
if (data.httpstatus == 200) {
if (JQTWEET.search) data = data.statuses;
var text, name, img;
try {
// append tweets into page
for (var i = 0; i < JQTWEET.numTweets; i++) {
img = '';
url = 'http://twitter.com/' + data[i].user.screen_name + '/status/' + data[i].id_str;
try {
if (data[i].entities['media']) {
img = '<img src="' + data[i].entities['media'][0].media_url + '" />';
}
} catch (e) {
//no media
}
var textoMostrar = JQTWEET.template.replace('{TEXT}', JQTWEET.ify.clean(data[i].text) ).replace('{USER}', data[i].user.screen_name).replace('{IMG}', img).replace('{URL}', url );
/*.replace('{AGO}', JQTWEET.timeAgo(data[i].created_at) ) */
//alert(JQTWEET.timeAgo(data[i].created_at));
$(JQTWEET.appendTo).append( JQTWEET.template.replace('{TEXT}', JQTWEET.ify.clean(data[i].text) )
.replace('{USER}', data[i].user.screen_name)
.replace('{NAME}', data[i].user.name)
.replace('{IMG}', img)
.replace('{PROFIMG}', data[i].user.profile_image_url)
/*.replace('{AGO}', JQTWEET.timeAgo(data[i].created_at) )*/
.replace('{URL}', url )
);
if ( (JQTWEET.numTweets - 1) == i) {
$(JQTWEET.appendTo).find(".item").last().addClass("last");
}
}
} catch (e) {
//item is less than item count
}
if (JQTWEET.useGridalicious) {
//run grid-a-licious
$(JQTWEET.appendTo).gridalicious({
gutter: 13,
width: 200,
animate: true
});
}
} else alert('no data returned');
}
});
callback();
},
showHideTweets: function() {
alert("hola");
var ojeto = $(JQTWEET.appendTo).find(".item").first();
$(JQTWEET.appendTo).find(".item").first().css("display", "block");
},
The problem is that if a call functions like this:
$(document).ready(function(){
JQTWEET.loadTweets();
JQTWEET.showHideTweets();
});
Second function executes before tweets has been loaded, so it have nothing to search in, because I can see the alert("hola") working, but Ojeto is 0.
I was trying to create some kind of callback inside loadTweets(); but I could not.

The callback isn't a bad idea.
change loadTweets to look like this:
loadTweets: function(callback) {
And call it here:
$.ajax({
...
success: function(data, textStatus, xhr) {
...
if (callback) callback();
}
});
And then in your DOM ready callback:
$(document).ready(function(){
JQTWEET.loadTweets(JQTWEET.showHideTweets);
});
Your other option (which I actually prefer, in general) is to use a deferred object:
loadTweets: function(callback) {
var def = $.Deferred();
...
$.ajax({
...
success: function(data, textStatus, xhr) {
...
def.resolve();
}
});
return def.promise();
}
...
$(document).ready(function(){
JQTWEET.loadTweets().done(JQTWEET.showHideTweets);
});

Try jQuery methods chaining:
$(document).ready(function(){
JQTWEET.loadTweets().showHideTweets();
});

Related

When submitting an ajax request, how can you "put the original request on hold" temporarily until a condition is met?

I am wanting to implement a recaptcha process that captures all ajax requests before they go through - the desired process would be as follows:
User completes an action which is going to cause an ajax request of some sort.
If the user has already completed the recaptcha process, the ajax request proceeds without further delay
If the user has not completed the recaptcha process, put the ajax request "on hold" temporarily until the recaptcha process is completed, then continue the ajax request.
I have got things to a state where I intercept the call, however I don't know how to put it on hold temporarily. Here's the relevant code:
<script>
var captchaValidated = null;
var currentRequests = [];
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
if (options.url != "/ValidateCaptcha") {
if (captchaValidated == null || captchaValidated == false) {
if (captchaValidated == null){
openRecaptcha();
} else {
verifyCaptcha(); //see async question in method
}
if (!captchaValidated) {
jqXHR.abort();
} else {
//let the original request proceed now - but how?!
}
}
}
});
function verifyCaptcha() {
var grecaptcha = $("g-recaptcha-response");
var encodedResponse;
if (grecaptcha != null) {
encodedResponse = grecaptcha.val();
$.ajax({
async: false, //set to false so that the calling method completes rather than async - what do you think?
headers: headers,
cache: false,
url: "/ValidateCaptcha",
type: 'POST',
contentType: 'application/json',
success: function (data) {
//parse the data - did we get back true?
captchaValidated = data;
},
error: function (raw, textStatus, errorThrown) { captchaValidated = null; alert("Validate ReCaptcha Error: " + JSON.stringify(raw)); },
data: JSON.stringify({ "encodedResponse": encodedResponse })
});
}
}
function invalidateCaptcha(){
captchaValidated = null;
}
function openRecaptcha() {
grecaptcha.render('recaptcha', {
'sitekey': "thekey",
'callback': verifyCaptcha,
'expired-callback': invalidateCaptcha,
'type': 'audio image'
});
$("#recaptchaModal").modal('show');
}
</script>
Any suggestions of how to proceed would be appreciated, thanks in advance!
Thank you #Loading and #guest271314 for your help in pointing me in the right direction that helped me get things figured out. I've pasted how I accomplished it below - perhaps it will be of help to someone else. Of course if anyone would like to weigh in on my implementation please do.
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCaptcha&render=explicit&hl=en" async defer></script>
<script>
var captchaValidated = null;
var currentRequests = [];
var captchaPrompted = false;
var captchaReady = false;
var resetCaptcha = false;
function onloadCaptcha() {
captchaReady = true;
captcha = grecaptcha.render('recaptcha', {
'sitekey': '<yoursitekey>',
'callback': verifyCaptcha,
'expired-callback': invalidateCaptcha,
'type': 'audio image'
});
}
var deferredCaptcha = null;
var promiseCaptcha = null;
var captcha = null;
function openRecaptcha() {
if (!captchaReady) {
setTimeout(openRecaptcha, 50);
}
if (captchaPrompted) {
return;
}
captchaPrompted = true;
var captchaTimer = setInterval(function () {
if (captchaValidated != null) {
if (captchaValidated) {
deferredCaptcha.resolve();
} else {
deferredCaptcha.reject();
captchaValidated = null;
}
}
}, 100);
if (resetCaptcha) {
captcha.reset();
}
deferredCaptcha = $.Deferred();
promiseCaptcha = deferredCaptcha.promise();
promiseCaptcha.done(function () {
//captcha was successful
clearInterval(captchaTimer);
//process the queue if there's items to go through
if (currentRequests.length > 0) {
for (var i = 0; i < currentRequests.length; i++) {
//re-request the item
$.ajax(currentRequests[i]);
}
}
});
promiseCaptcha.fail(function () {
//captcha failed
clearInterval(captchaTimer);
currentRequests = []; //clear the queue
});
$("#recaptchaModal").modal('show');
}
function verifyCaptcha() {
resetCaptcha = true;
var response = $("#g-recaptcha-response").val();
var encodedResponse;
// confirm its validity at the server end
$.ajax({
headers: headers,
cache: false,
url: "/ValidateCaptcha",
type: 'POST',
contentType: 'application/json',
success: function (data) {
captchaValidated = data;
if (!data) {
captchaPrompted = false;
}
},
error: function (raw, textStatus, errorThrown) { captchaValidated = false; captchaPrompted = false; alert("WTF Validate ReCaptcha Error?!: " + JSON.stringify(raw)); },
data: JSON.stringify({ "encodedResponse": response })
});
}
function invalidateCaptcha(){
deferredCaptcha.reject();
captchaValidated = null;
resetCaptcha = true;
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (settings.url == '/ValidateCaptcha' || captchaValidated) {
// we're validating the captcha server side now or it's already been validated - let it through
} else {
if (typeof settings.nested === 'undefined'){
settings.nested = true; //this flag is to determine whether it's already in the queue
currentRequests.push(settings); //add the request to the queue to be resubmitted
//prompt them with the captcha
openRecaptcha();
}
return false; // cancel this request
}
}
});
</script>
At $.ajaxPrefilter() use .then() chained to openCaptcha to call verifyCaptcha
if (captchaValidated == null){
openRecaptcha().then(verifyCaptcha);
}
at verifyCaptcha use .is() with parameter "*" to check if an element exists in document
if (grecaptcha.is("*")) {
at openRecaptcha(), if grecaptcha.render does not return asynchronous result return jQuery promise object using .promise(); else chain to grecaptcha.render and $("#recaptchaModal").modal('show'); using $.when()
return $("#recaptchaModal").modal('show').promise()
or
return $.when(grecaptcha.render(/* parameters */)
, $("#recaptchaModal").modal('show').promise())
Something like this? (pseudo-code)
verified = false;
$('#myButton').click(function(){
if (!verified) verify_by_captcha();
if (verified){
$.ajax(function(){
type: 'post',
url: 'path/to/ajax.php',
data: your_data
})
.done(function(recd){
//ajax completed, do what you need to do next
alert(recd);
});
}
});//end myButton.click

jquery iframe load dynamically

I am using following jquery script to load another url after successful ajax request.
$(document).ready(function() {
var $loaded = $("#siteloader").data('loaded');
if($loaded == false){
$("#siteloader").load(function (){
if(ad_id != undefined){
var req_url = base_url+'ajax/saveclick/'+ad_id+'/';
var preloader = $('#preloader');
var reqloader = $('#reqloader');
$.ajax({
url: req_url,
type: 'GET',
beforeSend: function() {
$(preloader).show();
$('#adloading').remove();
},
complete: function() {
$(preloader).hide();
},
success: function(result) {
$(reqloader).html(result);
$("#siteloader").data("loaded", "true");
$("#siteloader").attr("src", base_url+'userpanel/cpa/'+ad_id+'/');
}
});
}
else{
$('#reqloader').html('<span class="text-danger">Invalid Approach!</span>');
}
});
}
});
<iframe src="remote_url" id="siteloader"></iframe>
I don't want to run ajax again after changing src on iframe and i have also tried to stop it by $("#siteloader").data("loaded", "true");
Please suggest me a good solution for this. thanks.
If you only want to execute the "load" handler once
Simply add the line
$("#siteloader").unbind('load');
In the success callback.
If you want the "load" handler to be executed on each src change, you may do something like that :
$(document).ready(function () {
$("#siteloader").load(function () {
// Move the test in the event Handler ...
var $loaded = $("#siteloader").data('loaded');
if ($loaded == false) {
if (ad_id != undefined) {
var req_url = base_url + 'ajax/saveclick/' + ad_id + '/';
var preloader = $('#preloader');
var reqloader = $('#reqloader');
$.ajax({
url: req_url,
type: 'GET',
beforeSend: function () {
$(preloader).show();
$('#adloading').remove();
},
complete: function () {
$(preloader).hide();
},
success: function (result) {
$(reqloader).html(result);
$("#siteloader").data("loaded", "true");
$("#siteloader").attr("src", base_url + 'userpanel/cpa/' + ad_id + '/');
}
});
}
else {
$('#reqloader').html('<span class="text-danger">Invalid Approach!</span>');
}
}
});
});
Maybe your ad_id variable is not well defined / changed ...

Why trigger and click do not work in this case?

I have a piece of code that does:
$('td.unique').live('click', function () {
//function logic here
});
This works fine on I click on the td of my table. All fine!
Now I would like to be able to have the same functionality programatically in certain cases without the user actually pressing click.
I have tried:
$(document).ready(function() {
$(".clearButton").click( function () {
var username = $(this).closest('tr').find('input[type="hidden"][name="uname"]').val();
var user_id = $(this).closest('tr').find('label').val();
var input = [];
input[0] = {action:'reset', id:user_id,user:username,};
$.ajax({
url: 'updateprofile.html',
data:{'user_options':JSON.stringify(input)},
type: 'POST',
dataType: 'json',
success: function (res) {
if (res.status >= 1) {
//all ok
console.log("ALL OK");
$(this).closest('tr').find('.unique').trigger('click');
$(this).closest('tr').find('td.unique').trigger('click');
$(this).closest('tr').find('td.unique').click();
}
else {
alert('failed');
}
}
});
This button is in the same row that the td.unique is
None of these work. Why? Am I doing it wrong? Is the function that I have bind in live not taken into account when I click this way?
You need to cache the $(this) inside the ajax function.
var $this = $(this);
the $(this) inside the ajax function will not refer to the element that is clicked
$(".clearButton").click(function () {
var $this = $(this);
var username = $this.closest('tr').find('input[type="hidden"][name="uname"]').val();
var user_id = $this.closest('tr').find('label').val();
var input = [];
input[0] = {
action: 'reset',
id: user_id,
user: username,
};
$.ajax({
url: 'updateprofile.html',
data: {
'user_options': JSON.stringify(input)
},
type: 'POST',
dataType: 'json',
success: function (res) {
if (res.status >= 1) {
console.log("ALL OK");
$this.closest('tr').find('.unique').trigger('click');
$this.closest('tr').find('td.unique').trigger('click');
$this.closest('tr').find('td.unique').click();
} else {
alert('failed');
}
}
});
});

How can I handle errors in AJAX in jquery

How can I handle errors in AJAX?
In my code, the else condition containing console.log is not executed even when the departments.json file is not loaded. I checked it by deleting the departments.json file from where it is loaded into the code.
My code is:
$.getJSON("departments.json?" + new Date().getTime(), {}, function(departments, status, xhr) {
if (xhr.status == 200) {
var numericDepts = [];
var nonNumericDepts = [];
for(dept in departments) {
$("#kss-spinner").css({'display':'none'});
if (isNaN(departments[dept].depNo)) {
if (isNaN(parseInt(departments[dept].depNo,10)))
nonNumericDepts[nonNumericDepts.length] = departments[dept];
else
numericDepts[numericDepts.length] = departments[dept];
}
else
numericDepts[numericDepts.length] = departments[dept];
}
numericDepts.sort(cmp_dept);
nonNumericDepts.sort(function(dept1,dept2) {
return dept1.depNo.toLowerCase() - dept2.depNo.toLowerCase();
});
departments.sort(cmp_dept);
var k = 0;
$.each(numericDepts.concat(nonNumericDepts), function() {
if (k % 2 == 0) {
$('<p class="odd" onClick="selectTag(this,\'' + this.id + '\', 1)">' + this.depNo + '</p>').appendTo($(".scroller", $("#br1")));
}
else {
$('<p class="even" onClick="selectTag(this,\'' + this.id + '\', 1)">' + this.depNo + '</p>').appendTo($(".scroller", $("#br1")));
}
k++;
});
$("#kss-spinner").css({'display':'none'});
}
else {
console.log(xhr.status);
console.log(xhr.response);
console.log(xhr.responseText)
console.log(xhr.statusText);
console.log('json not loaded');
}
});
You could just use the generic ajax() function:
$.ajax({
url: url,
dataType: 'json',
data: data,
success: successCallback,
error: errorCallback
});
You will need to use the fail() method in order to accomplish that.
Example:
$.get("test.php")
.done(function(){ alert("$.get succeeded"); })
.fail(function(){ alert("$.get failed!"); });
if you need a generic error handler use
$.ajaxSetup({
error: function(xhr, status, error) {
// your handling code goes here
}
});
JQuery's getJSON function is an abstraction over the regular .ajax() method - but it excludes the error callback.
Basically, the function you define is only called if the call is successful (that's why it never gets to the else part).
To handle errors, set an error handler before like this:
$.ajaxError(function(event, jqXHR, ajaxSettings, thrownError) { alert("error");});
Whenever an AJAX request completes with an error, the function will be called.
You can also append the .error at the end of your getJSON call:
$.getJSON("example.json", function() {
(...)
}).error(function() { (...) });
The $.getJSON() function is just a special purpose version of the more general .ajax() function.
.ajax() function will give you the extra functionality you desire (such as an error function). You can read more documentation here http://api.jquery.com/jQuery.ajax/
$.ajax({
url: "departments.json?" + new Date().getTime(),
dataType: 'json',
success: function(departments){
var numericDepts = [];
var nonNumericDepts = [];
for(dept in departments)
{
$("#kss-spinner").css({'display':'none'});
if(isNaN(departments[dept].depNo))
{
if(isNaN(parseInt(departments[dept].depNo,10)))
nonNumericDepts[nonNumericDepts.length]=departments[dept];
else
numericDepts[numericDepts.length]=departments[dept];
}
else
numericDepts[numericDepts.length]=departments[dept];
}
numericDepts.sort(cmp_dept);
nonNumericDepts.sort(function(dept1,dept2) {
return dept1.depNo.toLowerCase() - dept2.depNo.toLowerCase();
});
departments.sort(cmp_dept);
var k=0;
$.each(numericDepts.concat(nonNumericDepts),function(){
if(k%2==0){
$('<p class="odd" onClick="selectTag(this,\''+this.id+'\',1)">'+this.depNo+'</p>').appendTo($(".scroller",$("#br1")));
} else {
$('<p class="even" onClick="selectTag(this,\''+this.id+'\',1)">'+this.depNo+'</p>').appendTo($(".scroller",$("#br1")));
}
k++;
});
$("#kss-spinner").css({'display':'none'});
},
error: function(xhr, textStatus, errorThrown) {
console.log(xhr.status);
console.log(xhr.response);
console.log(xhr.responseText)
console.log(xhr.statusText);
console.log('json not loaded');
}
});​

ajax get null value

My code can get data in Chrome console
but cant get data in my program
code like this:
$(document).ready(function () {
var theme = '';
var source = [];
var rsps = '';
$.ajax({
url: '#Url.Content("~/Home/RoleMenus")',
type: "GET",
cache: false,
success: function(response, status, xhr) {
rsps = response;
source = eval(response);
},
error: function(XMLHttpRequest,textStattus,errorThrown) {
$('#jqxErrorMsg').html(errorThrown);
}
});
for(var src in source) {
if (src.items.legth > 0) {
src.expanded = true;
}
}
// Create jqxTree
$('#jqxTree').jqxTree({ source: source, theme: theme});
$('#jqxTree').bind('select', function (event) {
var args = event.args;
var item = $('#jqxTree').jqxTree('getItem', args.element);
for (var menu in source[0]) {
if (item.label == menu.label) {
window.location = menu.actionUrl;
//break;
}
}
});
});
=====update=====
the response is right, if i move
// Create jqxTree
$('#jqxTree').jqxTree({ source: source, theme: theme});
into success: function(response, status, xhr) {}
the menu shows correctly
but the source variable still has no value outside
=====solved====
for (var menu in source[0])
should be
for (int i=0;i<source[0].length;i++)
The ajax call is async so source variable may not be initialized yet. Try putting
for(var src in source) {
if (src.items.legth > 0) {
src.expanded = true;
}
}
// Create jqxTree
$('#jqxTree').jqxTree({ source: source, theme: theme});
in the succes function.

Categories

Resources