How to work with JSONP to call back the function? - javascript

I am trying to communicate with a server using JSONP call back.
Here is my code
$('.icwsDownloadRecording').click(function(){
var id = $(this).attr('data-recordingid');
$.ajax({
type: 'GET',
url: 'http://example.com/Default2.aspx',
data: {'ID': id},
dataType: 'jsonp',
cache: false,
timeout: 40000,
crossDomain:true,
jsonp: "MyCallbackFunction",
});
});
function MyCallbackFunction(data)
{
//process data further
console.log(data);
if(!data || data.url.length < 5){
return;
}
var $preparingFileModal = $("#preparing-file-modal");
$preparingFileModal.dialog({ modal: true });
$.fileDownload( data.url, {
successCallback: function (url) {
$preparingFileModal.dialog('close');
},
failCallback: function (responseHtml, url) {
$preparingFileModal.dialog('close');
$("#error-modal").dialog({ modal: true });
}
});
return false; //this is critical to stop the click event which will trigger a normal file download!
}
The issue here is that I keep getting this message in the console
ReferenceError: MyCallbackFunction is not defined
I do have this defined as you can see in my code above
The server respond looks like this
MyCallbackFunction("{'URL': 'http:\/\/example.com:8106\/ghjgj3835396265336634646562363030303122226D616C686179656B22535353557DBE0C305645E2DE110AA1D7F8792E96A3'}");
how can I correct this issue?
EDITED
This is my code after Quentin Answer , this is my new code
$(function(){
$('.icwsDownloadRecording').click(function(){
var id = $(this).attr('data-recordingid');
$.ajax({
type: 'GET',
url: 'http://example.com/Default2.aspx',
data: {'ID': id},
dataType: 'jsonp',
timeout: 40000,
success: function(data){
//process data further
console.log(data);
if(!data || data.url.length < 5){
return;
}
var $preparingFileModal = $("#preparing-file-modal");
$preparingFileModal.dialog({ modal: true });
$.fileDownload( data.url, {
successCallback: function (url) {
$preparingFileModal.dialog('close');
},
failCallback: function (responseHtml, url) {
$preparingFileModal.dialog('close');
$("#error-modal").dialog({ modal: true });
}
});
return false; //this is critical to stop the click event which will trigger a normal file download!
}
});
});
});

Unless you have all of that code wrapped in another function, that should work.
Using a hardcoded function name is bad practise though.
Update:
$(function(){
You do have all that code wrapped in another function.
Remove this:
jsonp: "MyCallbackFunction",
Replace it with:
success: MyCallbackFunction
Or you could put an anonymous function expression there instead (as you have done in your edit)
Let jQuery generate a unique function name (which protects you from race conditions) and allow the server to use the callback query string argument to determine what function name to use.
MyCallbackFunction is in the same scope as the ajax call, so it will be available to the function (which can copy it to a suitably named global).
After you fix that, you have an additional problem:
MyCallbackFunction("{'URL':
Your response is JSON encoded in a JavaScript string, but you are trying to treat it as a JavaScript object.
Either:
Fix the server so it doesn't stringify the JSON or
Run the first argument through JSON.parse
crossDomain:true,
Remove that. It doesn't do anything here. (All it does is, when using XHR (which you aren't using) to the same origin (which you aren't targeting), suppress the custom headers that aren't typically allowed on a cross-origin request so that you can perform an HTTP redirect to a different origin).
cache: false,
That's the default for JSONP requests. Including it is pointless.
return false; //this is critical to stop the click event which will trigger a normal file download!
If you want to stop the click event, then you need to return false from the click event handler function (not the Ajax success handler).
You can't wait until the Ajax function has run and got a response before doing that. Ajax is asynchronous.

Related

Calculating the Time of an ajax Response and use that time in SetTimeout function

I am trying to get the response time of an ajax request and use it in a setTimeout() function, this function displays a loader that is suppose to keep loading until we get the response.
Here's my function :
$("#recalculer").click(function(){
ajax_call();
setTimeout(function()
{
$("#divgris").fadeTo(0,1);
$("#loadingdiv2").hide();
}, 5000);
});
And here's my ajax request :
function ajax_call()
{
var resultat;
var duree_souhaitee= $("#duree").val();
var apport_personnel= $("#apport").val().replace(/\s+/g, '');
var prix_achat_bien=$("#prix").val().replace(/\s+/g, '');
$.ajax({
type: "POST",
url: "/iframe/rest-assurance",
data : {
"duree_souhaitee" : duree_souhaitee,
"apport_personnel" : apport_personnel,
"prix_achat_bien" : prix_achat_bien
},
dataType: 'json',
xhrFields: {
withCredentials: true
},
async: true,
beforeSend: function(){
$("#actualiserAssurance").hide();
},
success: callback_assurance
});
}
For now i set a time of 5000 but i need to replace it with the ajax response time, how can I achieve that ?
I use always:
$("#loadingdiv2").show();
$.ajax(
...
).always(function(){ $("#loadingdiv2").hide(); });
If you want to separate it from the Ajax call I would use a custom event.
$("#recalculer").click(function(){
ajax_call();
});
$("body").bind('custom.ajaxStart', function(){ $("#loadingdiv2").show(); });
$("body").bind('custom.ajaxStop', function(){ $("#loadingdiv2").hide(); });
function ajax_call(){
$('body').trigger('custom.ajaxStart');
$.ajax(..).always(function(){ $('body').trigger('custom.ajaxStop'); });
}
The always callback is triggered even on a 404, relying on timing never works well for me.
Using an event gives you the flexibility of calling the loading deal, from anywhere.
Meaby the you can use:
console.time(label);
and
console.timeEnd(label);
more info can be found here.
Goodluck!
use
var afterfnc = ()=>{
$("#divgris").fadeTo(0,1);
$("#loadingdiv2").hide();
}
and then set
callback_assurance = afterfnc
in ajax call

nested $.ajax in inside $.ajax - very strange issue

Let's start from here - I have defined base setting for all future AJAX-requests, like this
$.ajaxSetup({
beforeSend : function(){
$("#ajax-loader").dialog({
modal : true
});
},
complete : function(){
$("#ajax-loader").dialog("hide");
}
});
Now, I have a form where my users can upload their bio and pictures. When a form is valid, then I allow to upload their pictures. It works this way:
$("#send").click(function(e){
e.preventDefault();
$.ajax({
data : $("#bio-form").serialize(),
url : "/validate.ajax",
success : function(response) {
// If AJAX-validator returns "1" then a form is valid
if (response == "1"){
// Now I start to upload photos, like
// this
var formData = new FormData(document.getElementById('upload-form'));
$.ajax({
processData : false,
contentType : false,
cache : false,
data : formData,
success : function(response) {
alert(response);
}
});
}
}
});
});
The problem
Once ajax-uploading starts, I expect a $("#ajax-loader") to be showed. On complete this should be closed automatically according to the settings I defined in $.ajaxSetup.
BUT...
It appears and disappears right after 1 sec on file uploading. I know that ajax request isn't completed, because I get successfuly message after 1-2 mins (that photos uploaded).
I tried to change async: false and it started to work as expected === a modal appears when uploading files to server and disappers when done:
data : formData,
async : false,
processData : false,
Question
Is it possble to do the same when async : true is set to its default mode(true)? I don't want a browser to be frozen when uploading in progress!
As you've discovered, Ajax is an asynchronous technology - meaning it runs on its own schedule
Making Ajax synchronous causes all sorts of problems (using async:false actually causes the browser to freeze whilst the request is performed)
There are several issues I'd mention you may want to fix:
Why Nested Ajax?
Nesting Ajax requests, in this current state of the web, is, in my opinion, bad practice. It generally means you've got something wrong with your system. Concurrent requests are fine - but nested I'd avoid like the plague
Ajax Callbacks
If you can get your Ajax requests down to a single entity, I'd look at using Ajax Callbacks to create your desired result
Ajax callbacks work by using Ajax as part of a function, where the success & error callbacks are handled by several differnt parts of your parent function. Here's an example:
function create_modal(o){
fetch_modal(o.ajax, function(data){
//do success stuff here
}, function(data){
//do error stuff here
});
}
function fetch_modal(link, success, error) {
$.ajax({
url: link,
success: function(data) { success(data); },
error: function(data) { error(data); }
});
}
The problem is ajaxSetup. You have to follow enable/disable method on uploading photo. Let me clearup the understanding. You want to show the loader to intimate the user that he/she has to wait until validation process finishes. Once the validation get success you are starting to upload file. While uploading file, you want to allow the user interact with page.
To achieve this you have to do as follows,
function ajaxSetup(mode) {
var options = {};
if (mode === "on") {
options = {
beforeSend : function() {
$("#ajax-loader").dialog({
modal : true
});
},
complete : function() {
$("#ajax-loader").dialog("hide");
}
};
} else {
options = {
beforeSend : function() {
},
complete : function() {
}
};
}
$.ajaxSetup(options);
}
And Make your ajax request as follows,
ajaxSetup("on");
$("#send").click(function(e) {
e.preventDefault();
$.ajax({
data : $("#bio-form").serialize(),
url : "/validate.ajax",
success : function(response) {
// If AJAX-validator returns "1" then a form is valid
if (response == "1") {
// Now I start to upload photos, like
// this
var formData = new FormData(document.getElementById('upload-form'));
ajaxSetup("off"); //Here second-time seem-less displaying of loader will be avoided.
$.ajax({
processData : false,
contentType : false,
cache : false,
data : formData,
success : function(response) {
alert(response);
}
});
ajaxSetup("on");
}
}
});
});
Note: I am not tested code. Please make sure, if any syntax or typo error.

jQuery access vaules of global variable form one function to another

I am working in jQuery and I have a variable that I declared as global in one function and when I alert it it gives me right result but now I want to access the same variable in another function and alert it in another function it gives me empty result mean I cannot access it over there. I know about the scope of a variable but to overcome it I decleared variable as global but I am still unable to access it.
Here is my first function:
var employee_email = '';
function showCustomer()
{
// fire off the request to ajax_stufflist.php
request = $.ajax({
url: "ajax_stufflist.php?"+url,
type: "post",
success: function(data){
if(data != ''){
var response = $(data).find("#gmp_stuff").html();
employee_email = $(data).find(".EMP_EMAIL>span").html();
//alert(employee_email);
$("#user_responses").html(response);
$(function() {
$("#user_responses").dialog({
dialogClass:'transparent',
resizable: false,
draggable: false,
modal: true,
width: 1000,
autoOpen: false,
overlay: { opacity: 0 }
});
$('#user_responses').dialog('open');
$('#user_responses').css('display','');
});
}
},
error:function(){
alert("failure");
$("#user_responses").html('error occured');
}
});
}
In this function the variable employee_email is decleared above the function and I want to access the same variable with value in other function just next to it in same script tag.
function sendEmail(){
alert(employee_email );
request = $.ajax({
url: "send_email.php?"+employee_email ,
type: "post",
success: function(data){
$("#email_responses").html();
},
error:function(){
alert("failure");
$("#email_responses").html('error occured');
}
});
}
Kindly tell me what's wrong with it. Thanks in advance for any kind of help.
This is not a problem of scope. If it would have been, you would have got an error in your console. But you are getting an empty result because either the AJAX call is not complete yet or it has not been able to change the value due to some error there. Try this.
Define:
var flag = false;
Your success function should be:
success: function (data) {
if (data != '') {
var response = $(data).find("#gmp_stuff").html();
employee_email = $(data).find(".EMP_EMAIL>span").html();
//alert(employee_email);
$("#user_responses").html(response);
//$(function () {
$("#user_responses").dialog({
dialogClass: 'transparent',
resizable: false,
draggable: false,
modal: true,
width: 1000,
autoOpen: false,
overlay: { opacity: 0 }
});
$('#user_responses').dialog('open');
$('#user_responses').css('display', '');
//});
flag = true;
}
}
And sendEmail() can be:
function sendEmail(){
if(flag)
{
request = $.ajax({
url: "send_email.php?"+employee_email ,
type: "post",
success: function(data){
$("#email_responses").html();
},
error:function(){
alert("failure");
$("#email_responses").html('error occured');
}
});
}
else
alert('Sending email is unavailable currently. PLease try after some time.');
}
Even though this have been answered hundreds of times on SO, I can give you a short explanation.
Since you're dealing with 2 asynchronous calls, you can never access data from the first call in a normal syncronous flow.
Make your first function return your $.ajax
function showCustomer(){
return $.ajax({ /* ... */ });
And access the data returned in a callback:
showCustomer().done(function(data){
console.log($(data).find(".EMP_EMAIL>span").html());
});
This assumes that you're using jQuery 1.5 or above, where the ajax calls exposes a promise.
An other alternative would be to nest the ajax calls (call the second one in the first ones success handler).
You're updating the value employee_email through AJAX call. As soon as first function is called, it makes AJAX call and moves to second function. The second function won't see the value change yet and employee_email doesn't change at all.
You've 2 options -
Use second function in done of first function.
Use Deferred object in first call and on done of it call the second function.

Can I continue with a previous prevent link?

I have this link:
$('.popup-window').click(function (e) {
e.preventDefault();
$.ajax({
...
})
});
which is a .NET LinkButton (a link that call a javascript, not a real href). I want to prevent Default if ajax return some (let say, false). Else, if true, continue with that link handler.
How can I do it?
P.S. I need that e.preventDefault(); at the beginning, else .NET handler will act immediatly.
You can use the __doPostBack() js function to trigger the postback in your AJAX callback.
The only thing is that you need to pass in the id of the control causing the postback, e.g.
__doPostBack('btnPopup', null);
you can see more on this function in this question: How to use __doPostBack()
I think I understand what you're looking for.
Here's my idea on it: use a data attribute on the DOM element to decide weither default event should be prevented or not. Initially, the event is prevented but the ajax has the power to "unlock?" it, then fire it again. It's a little bit of custom work but it may do the trick:
var $popupWindow=$('popup-window');
// initially "tell" the LinkButton to prevent default
$popupWindow.data('prevent-default', 1);
// the click event (initially prevents default)
$popupWindow.click(function(e){
var $this=$(this);
if ($this.data('prevent-default')==0) { // if "unlocked"
// "lock" it again (default isn't prevented)
$this.data('prevent-default', 1);
} else { // if "locked"
// default is prevented
e.preventDefault();
// test if it should be unlocked
$.ajax({
// ...
}).done(function(data){
if (data.length>0 && data.response==false) {
// set the attribute so it shouldn't prevent default
$this.data('prevent-default', 0);
// trigger this click (should let the event fire completely)
$this.trigger('click');
}
});
}
});
UPDATE:
An alternative could be to add a Page Method.
(See: Using jQuery to directly call ASP.NET AJAX page methods)
This would reduce the mechanics to somethink like this:
$('popup-window').click(function(e){
e.preventDefault();
$.ajax({
// ...
}).done(function(data){
if (data.length>0 && data.response==false) {
$.ajax({
type: "POST",
url: "YourPage.aspx/YourMethod",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
// Replace the div's content with the page method's return.
$("#Result").text(msg.d);
}
});
}
});
});
$('.popup-window').click(function (e) {
data = '?sample=1' //serialized data here
callback = function(json){
if(json.returnVar!=true){ //check if returnVar is not true
e.preventDefault(); //prevent redirect if not true
}
};
$.ajax({
type: 'POST',
url: "../ajaxcall.php", //the url to call for ajax here
data: data,
success: callback,
dataType: 'json'
});
});
Try this, let me know if you can't understand the code

getJSON timeout handling

I am using jQuery getJSON() function. This function getting data with no problem. But sometimes waiting, waiting waiting... And my loading bar showing loading loading loadin at center of page.
So jQuery ajax() function have an timeout variable. But i want to use getJSON function. And i think that i can use ajaxStart() and ajaxStop() functions. But how?
$('.loadingDiv')
.hide()
.ajaxStart(function() {
$(this).fadeIn();
setTimeout("throw '';",15000) //i used this but didn't work
setTimeout("return;",15000) //i used this but didn't work
setTimeout("abort();",15000) //i used this but didn't work.(Abort all ajax events)
})
.ajaxStop(function() {
$(this).fadeOut();
});
getJSON() returns a promise on which you can call the abort function :
var p = $.getJSON(..., function(){ alert('success');});
setTimeout(function(){ p.abort(); }, 2000);
EDIT : but if your goal is just to abort if it takes too much time, then lethal-guitar's answer is better.
getJSON() is just a shorthand for the following:
$.ajax({
dataType: "json",
url: url,
data: data,
success: success
});
So you could use $.ajax() and specify the timeout option as desired. See also: http://api.jquery.com/jQuery.getJSON/
As lethal-guitar mentioned getJSON() function is just an shorthand for $.ajax(). If you want to detect if a timeout has occurred rather than an actual error use the code below.
var request = $.ajax({
dataType: "json",
url: url,
data: data,
success: function( ) { },
timeout: 2000
}).fail( function( xhr, status ) {
if( status == "timeout" ) {
// do stuff in case of timeout
}
});
There's always the nuclear route as well:
//Set AJAX timeout to 10 seconds
$.ajaxSetup({
timeout: 10*1000
});
This will set all the AJAX requests your program makes (even via $.getJSON) to have a time out of 10 seconds (or what have you).
the setTimeout function executes a set of code after a specified number of milisecons in the global scope.
The getJSON function (per the jQuery documentation here http://api.jquery.com/jQuery.getJSON/) is shorthand for:
$.ajax({
dataType: "json",
url: url,
data: data,
success: success
});
so you would want to make your call like so:
$.ajax({
dataType: "json",
url: url,
data: data,
success: success,
timeout: 15000
});
$('.loadingDiv')
.hide()
.ajaxStart(function() {
$(this).fadeIn();
})
.ajaxStop(function() {
$(this).fadeOut();
});
I don't think any of these answers are ideal. I know this is years late, but what you want to do is use the success/error callback options of the .ajax(); method when receiving a JSONP response.
Example of how I would structure this:
// Call
$.ajax({
// URL you want to get
url: 'http://example.com/json?callback=?',
// Set a realistic time in milliseconds
timeout: 3000,
// Put in success callback function here, this example
// shows you the data you got back from the call
success: function(data) {
console.log(data);
},
// Put in an error handling function, just an alert in this case
error: function(badData) {
alert('The call was unsuccessful');
},
type: 'POST'
});

Categories

Resources