Problem with jQuery Calls in a Javascript Class with Callbacks - javascript

I'm using JavaScript, jQuery, and JSONP to make asynchronous, cross-domain WCF service calls. I've gotten this functionality successfully working, so I know that the problem I'm experiencing is not on the service side.
I had my test client site set up to make inline jQuery calls using the getJSON method, and it was working fine. However, I then tried to take the jQuery calls and put them into a JavaScript class. Now I'm having trouble getting callbacks to fire.
This works fine (the functions in the working example are added in script tags on the page itself):
function handleResponse(result) {
if (result.Success) {
// do something
}
else {
// do something else
}
}
function validate(serviceURL, data) {
$.getJSON(serviceURL + "/Validate?data=" + data + "&callbackHandler=?", handleResponse);
}
When I attempted to create a class to wrap this functionality in a separate .js include file, the callbacks don't fire. Here is the class code from the .js include file:
function serviceProxy(myServiceURL) {
this.serviceURL = myServiceURL;
this.validate = function(data, successCallback, failureCallback) {
$.getJSON(this.serviceURL + "/Validate?data=" + data + "&callbackHandler=?", function(result) {
if (result.Success) {
successCallback();
}
else {
failureCallback(result.ErrorMessage);
}
});
};
And here is the JavaScript that's written in script tags directly on the page to make the calls:
function handleSuccess() {
// do something
}
function handleFailure(message) {
// do something else
}
function validate(serviceURL, data) {
var proxy = new serviceProxy(serviceURL);
proxy.validate(data, handleSuccess, handleFailure);
}
When debugging, the getJSON call is executed, but the handleSuccess and handleFailure callbacks are never reached. Any advice would be greatly appreciated.
Thanks in advance,
Ben

Have you tried replacing:
if (result.Success) {
successCallback();
}
with:
if (result.Success) {
successCallback(result);
}

Related

JQuery autocomplete function causing reference error

I am using jquery auto complete functionality. But occasionally I get Reference error:function is undefined in IE but works in Chrome.
This is my code which calls a backend Java function.
jQuery('autocomplete').focus(function() {
var f = jQuery(this);
f.autocomplete({
minLength: 3,
source: function(request, response) {
var etype = jQuery("#type").val();
Util.getId(
function(data) {
if (!isUserSessionValid(data[0])) {
return;
}
response(exportRespToArray(data));
},
etype,
f.val(),
getLang()
);
}
});
});
Util.getId() is a backend java function that returns data back. On success, the code checks if user session is still valid, if not forward to login screen.
But occasionally IE displays reference error that exportRespToArray is undefined. Both the functions are clearly defined in the external js file which is imported into the jsp. The autocomplete function is initialized through document.ready function.
It's legacy code and I am no jQuery expert. I guess the success keyword inside the Util.getId() function is optional? Why do I get the reference error only in IE if the call was success?
Ok. Did some research and function(data) is a DWR callback function.I could probably add an errorHandler block to find out if any error is returned from server.
Util.getId(
etype,
f.val(),
getLang(), {
callback:function(data) {
if (!isUserSessionValid(data[0])) {
return; }
response(exportRespToArray(data));
},
errorHandler:function(message) {
alert("Error returned: " + message);
}
});

JQuery/Ajax and when/done/promise confusion

I am trying to accomplish the following:
1) Get data some source and "do something with it".
2) Get data some other source and "do something with it".
3) The datafetching should preferrably run asynchronous (at the same time ie. the second one should not wait for the first one to complete).
4) When both are completed, some business logic runs - but ONLY when they are completed.
I have created a small JSFiddle to show how I thought this could work - but unfortunately it does not:
a) The datafetching calls are executed sequentially.
b) The business logic from step 4 above executes before the datafetching has even begun...
Fiddle here: https://jsfiddle.net/LeifFrederiksen/emttmhm7/
$.when(
getOneThing(),
getAnotherThing()
).done(
function() {
console.log("Got it all");
$("#Output").append("<BR>Got it all");
}
);
function getOneThing() {
commonFunctionToGetStuff("oneKindOfThings",renderOneKindOfThings);
}
function getAnotherThing() {
commonFunctionToGetStuff("anotherKindOfThings",renderAnotherKindOfThings);
}
function commonFunctionToGetStuff (listTitle,successFunction) {
var url = "https://httpbin.org/get";
$.ajax({
url: url,
type: "GET",
headers: { "accept": "application/json;odata=verbose" }
}).success(function (data) {
console.log("Calling renderfunction for " + listTitle);
$("#Output").append("<BR>Calling renderfunction for " + listTitle);
successFunction(data);
console.log("Back from renderfunction for " + listTitle);
$("#Output").append("<BR>Back from renderfunction for " + listTitle);
});
}
function renderOneKindOfThings(data) {
// Do something with the data...
console.log("Doing oneKindOfThings.");
$("#Output").append("<BR>Doing oneKindOfThings.");
}
function renderAnotherKindOfThings(data) {
// Do something with the data...
console.log("Doing anotherKindOfThings.");
$("#Output").append("<BR>Doing anotherKindOfThings.");
}
Any help clearing up how the structure should be is highly appreciated.
I need to maintain the structure where the function that performs the actual Ajax call is kind of generic, and can be called by simple wrapper functions with parameters controlling what datasource to use - like it is in the example :-)
Regards
Leif
You need to return the promise from your commonFunctionToGetStuff-method and the methods that call it. Otherwise, you're passing in undefined into your when-function which will immediately execute the done-callback. Also you have a few erroneous callback names (it's done or then, not success).
function getOneThing() {
return commonFunctionToGetStuff("oneKindOfThings",renderOneKindOfThings);
}
function getAnotherThing() {
return commonFunctionToGetStuff("anotherKindOfThings",renderAnotherKindOfThings);
}
function commonFunctionToGetStuff (listTitle,successFunction) {
var url = "https://httpbin.org/get";
return $.ajax({...})
.then(function (data) { ...});
}

Returning function content after AJAX call

I'm using webuiPopover plugin, to set popover content, i'm using a function
$('.blob a').webuiPopover({
template: template,
trigger: 'hover',
type: 'async',
url: '/ajax/getprofileinfo.php?user=433',
content: function(requestData) {
//executed after successful ajax request.
//How I can make another ajax call and then return everything to content?
}
});
Now... I can do any kind of things inside this callback. But what if I want to make another AJAX request inside this function (in this case i want to download Mustache template so i can render it with requestData and THEN return its output from the function
I tried something like this
content: function(requestData) {
var template = '';
$.get('/tpl/usertemplate.mustache').done(function(templateData) {
template = Mustache.render(templateData, requestData);
});
return template;
}
Without any luck. How to do it correctly? I know i could just set async to false, but it isn't "the right way".
Looking at this plugin API, I can't see the way to do what you want. There is async.before and async.after properties. You can try to use them, also you can try to call setContent mannually after second request is done, like
content: function(requestData) {
vat that = this;
$.get(url).done(function (data){
that.setContent(Mustache.render(templateData, data));
});
}
But i'm not sure if it will work.
Newbie mistake :) Javascript is asynchronous!
What's wrong with your code :
$.get('/tpl/usertemplate.mustache').done(function(templateData) { // This is done FIRST
template = Mustache.render(templateData, requestData); // This is done whenever the GET is finished, so... THIRD
});
return template; // This is done SECOND - At this point, template is empty.
What you should do :
$.get('/tpl/usertemplate.mustache').done(function(templateData) {
template = Mustache.render(templateData, requestData);
return template;
});
Or even simpler :
$.get('/tpl/usertemplate.mustache').done(function(templateData) {
return Mustache.render(templateData, requestData);
});

Waiting for ajax response same function

I know that similar questions have been posted many times, however I've read many of them and can't find an answer to my problem.
I have a function that waits for an ajax request response. Many of you will ask why? Well, I'm using a Wizard Jquery Plugin which executes a function onLeaveAStepFunction when a step is left, then the wizard goes to the selected step if the return value from onLeaveAStepFunction is true; else it remains in the same step.
I'm doing this async: false for waiting and it works, but this is a bad design. Also, I can't use a blockUI plugin.
How can I do this?
Some code:
Initializing the wizard:
$("#wizard").smartWizard({
onLeaveStep : onLeaveStepFunction,
});
Calling the ajax request:
function onLeaveStepCallback(obj, context) {
nextStep = sendForm();
}
The ajax request:
var nextStep = false;
$.ajax({
url : path,
type : "POST",
async : false,
data : $("#" + idForm).serialize(),
success : function(data) {
$("#" + idDiv).html(data);
nextStep = !$("#" + idHiddenErrores).val())
}
});
Omitting the attributes. Please help me.
You could use the jQuery wait method. I took an example from docs page to highlight how you'd do it:
$.when( $.ajax( "/request.php" ) ).done(function( response ) {
// response argument resolved from ajax requests
// process any work after ajax call finishes
}
A link to docs page:
http://api.jquery.com/jquery.when/
I'm doing this async: false for waiting and it works, but this is a bad design also I can't use a blockUI plugin.
Unless your wizard is better designed and supports async callbacks (e.g., promise-returning ones), async:false is your only choice.
Consider switching to a different wizard, and don't forget to file a bug for the plugin that you're currently using.
One hackish work-around is to do it before leaveStep. Perhaps on showStep:
var wizard_next_step;
$("#wizard").smartWizard({
onShowStep : function (obj, context) {
onLeaveStepFunction(obj, context, function(nextStep){
wizard_next_step = nextStep;
});
},
onLeaveStep : function () {
return wizard_next_step;
}
});
You'd also need to modify your onLeaveStepFunction to accept a callback:
function onLeaveStepCallback(obj, context, callback) {
nextStep = sendForm(callback);
}
And your ajax function should then be:
$.ajax({
url : path,
type : "POST",
async : false,
data : $("#" + idForm).serialize(),
success : function(data) {
$("#" + idDiv).html(data);
callback( !$("#" + idHiddenErrores).val()) );
}
});
Now, it looks like you're drawing into the wizard window with this:
$("#" + idDiv).html(data);
I'm entirely sure if this is the case. But if it is then you cannot do this here (obviously because it's onShowStep which would overwrite current content). If this is so you should pass the data in the callback:
success : function(data) {
callback( data , !$("#" + idHiddenErrores).val()) );
}
Write the wizard like this:
var wizard_next_step;
var wizard_data;
$("#wizard").smartWizard({
onShowStep : function (obj, context) {
onLeaveStepFunction(obj, context, function(data, nextStep){
wizard_data = data;
wizard_next_step = nextStep;
});
},
onLeaveStep : function (obj, context) {
$("#" + idDiv).html(wizard_data);
return wizard_next_step;
}
});
The key is to call all the asynchronous functions and get the data long before you call all your synchronous functions.
Note: I don't know smart-wizard at all and not a serious jQuery user. The answer above is based on my 2 minutes reading smart-wizard documentation on github and my understanding of javascript. You will definitely need to modify my examples to make it work.

Extend a function stored in a variable

I have a large JavaScript project that makes several Ajax web service calls. The code to handle the web service calls comes from a shared external file.
To separate the web service from calling code, there is a global object to reference to the calling function like so
var doRemote ={};
$(document).ready(function(){
doRemote =getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
}
A simplified version of the getRemoteEndpoint, which is in a file shared by several other pages in addition to the one I'm working on is as follows:
function getRemoteEndpoint(url) {
return function(methodName, options) {
var extension = {
url: url + '/' + methodName,
data: {},
async: true
};
var combined = $.extend({}, extension, options);
combined.data = JSON.stringify(combined.data);
return $.ajax( combined );
};
}
I invoke the web service calls by the following code
doRemote('WebServiceMethodName',
{
success: function(data) {
alert('Web Service Returned' + data);
},
error: function(req, stat, err) {
alert('Error');
}
});
I have the need to execute a function before executing the getRemoteEndpoint call in only the page I'm working on. Instead of calling the function before each of the 30 web service calls, I'd like to add a line of code to the function. I've tried to replace the doRemote assignment with the following.
doRemote =function() {
DoTask();
return getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
};
DoTask is a named function in the program I'm working on. While it throws no errors, none of the Ajax calls work.
I tried to use the JQuery.extend function, but it didn't work either.
What am I doing wrong?
You have to actually call it to assign the result of getRemoteEndpoint to doRemote:
doRemote = (function() {
DoTask();
return getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
})();
Update:
doRemote = (function() {
var oldDoRemote = getRemoteEndpoint('https://someplace.org/MyWebService.aspx');
return function(a1, a2) {
DoTask();
oldDoRemote(a1, a2);
}
})();

Categories