Javascript callback from custom jQuery AJAX function - javascript

I have this jQuery code
(function () {
function load_page (pagename) {
$.ajax({
url: "/backend/index.php/frontend/pull_page/",
type: "POST",
data: {page: pagename},
success: function (json) {
var parsed = $.parseJSON(json);
console.log(parsed);
return parsed;
},
error: function (error) {
$('#content').html('Sorry, there was an error: <br>' + error);
return false;
}
});
}
...
var json = load_page(page);
console.log(json);
if (json == false) {
$('body').fadeIn();
} else {
document.title = json.pagename + ' | The Other Half | freddum.com';
$("#content").html(json.content);
$('#header-navigation-ul a:Contains('+page+')').addClass('nav-selected');
$('body').fadeIn();
}
})();
and, guess what, it doesn't work. The AJAX request fires fine, and the server returns valid JSON but the console.log(json); returns undefined and the js crashes when it gets to json.pagename.
The first console.log(parsed) also returns good data so it's just a problem with the return (I think).
I knew I was clutching at straws and would be extremely if this worked, but it doesn't. To be honest, I don't know how to program callback functions for this situation.
EDIT: This is my now updated code, which doesn't work either.
function load_page (pagename, callback) {
$.ajax({
url: "/backend/index.php/frontend/pull_page/",
type: "POST",
data: {page: pagename},
success: function (json) {
callback(json);
},
error: function (error) {
$('#content').html('Sorry, there was an error: <br>' + error);
var json = false;
callback(json);
}
});
}
(function () {
$('body').hide();
var page = window.location.hash.slice(1);
if (page == "") page = 'home';
load_page(page, function(json) {
var parsed = $.parseJSON(json);
console.log(parsed);
if (json.pagename == "" || json.pagename == null) {
document.title = 'Page Not Found | The Other Half | freddum.com';
$('body').fadeIn();
} else {
document.title = parsed.pagename + ' | The Other Half | freddum.com';
$("#content").html(parsed.content);
$('#header-navigation-ul a:Contains('+page+')').addClass('nav-selected');
$('body').fadeIn();
}
});
})();
I moved load_page into global namespace 'cos I needed it to be there. The console.log(parsed) returns what seems to be a valid json object, but console.log(parsed.content) yields undefined. #content isn't being set either. Any ideas? I'll be glad to do any testing.
Any help is greatly appreciated!

Because Ajax requests are asynchronous, the code following the $.ajax function invocation still executes, whether the request is finished or not, so you should accept a callback as a argument to load_page that is invoked when the request is finished:
function load_page (pagename, callback) {
$.ajax({
url: "/backend/index.php/frontend/pull_page/",
type: "POST",
data: {page: pagename},
success: function (json) {
var parsed = $.parseJSON(json);
console.log(parsed);
callback(parsed); //bingo
},
error: function (error) {
$('#content').html('Sorry, there was an error: <br>' + error);
}
});
}
load_page(page, function(json) {
console.log(json);
if (json == false) {
$('body').fadeIn();
} else {
document.title = json.pagename + ' | The Other Half | freddum.com';
$("#content").html(json.content);
$('#header-navigation-ul a:Contains('+page+')').addClass('nav-selected');
$('body').fadeIn();
}
});

Inside the definition of the load_page function there is no "return" statement, not directly at least hence by doing a var json = load_page(page); you'll end up with json = undefined. Ideally you should re-organize your code a little. There is more than one way of doing this but here is one:
(function () {
function mySuccess(json) {
var parsed = $.parseJSON(json);
console.log(json);
console.log(parsed);
document.title = parsed.pagename + " | The Other Half | freddum.com";
$("#content").html(parsed.content);
$("#header-navigation-ul a:Contains(" + page + ")").addClass("nav-selected");
$("body").fadeIn();
}
function myFailure(error) {
$('#content').html('Sorry, there was an error: <br>' + error);
$("body").fadeIn();
}
function load_page(pagename, onSuccess, onFailure) {
$.ajax({
url: "/backend/index.php/frontend/pull_page/",
type: "POST",
data: {
page: pagename
},
success: onSuccess,
error: onFailure
});
}
load_page(page, mySuccess, myFailure);
})();

The issue is because jQuery issues ajax calls asynchronously by default. Hence the next statement is executed even before the ajax call is complete after
var json = load_page(page);.
You can either make the calls synchronous by passing async:false in the config parameters and dealing with the retun value in the callback function.

try console.log before parsing to check what data is exactly coming. is it valid json
success: function (json) {
console.log(json);
var parsed = $.parseJSON(json);

It's an AJAX call, as in, the code is completed asynchronously. You need to put the console.log and any other use of the json variable in the success function.

Related

JQuery Ajax Anonymus Callback Function gets overwritten when called while ajax in progress

I have a timing or scope problem on this function call.. or no idea what.
AjaxHandlerByClass('url', {clientName: this.clientName}, function (response) { this code gets never called})
AjaxHandlerByClass('url', {clientName: this.clientName}, function (response) { This code gets called 2 times})
From this Function
function AjaxHandlerByClass(className, postData, callback, callbackFail) {
var timestamp = new Date().getTime();
var me = this;
me.backHandler = function (data) {
if (data)
if (data.responseJSON || data.debug) {
if (data.debug)
var debug = data.debug;
else if (data.responseJSON && data.responseJSON.debug)
var debug = data.responseJSON.debug;
if (window.console) {
for (var key in debug) {
if (debug.hasOwnProperty(key)) {
// console.log(debug[key]);
}
}
}
}
if (me.mode = 'callback') {
callback(data); //<--- this is the bug location
} else {
callbackFail(data);
}
};
this.ok = function (data) {
me.mode = 'callback';
me.backHandler(data)
}
this.notOk = function (data) {
me.mode = 'callbackFail';
me.backHandler(data)
}
$.ajax(
{
contentType: "application/json; charset=utf-8",
url: className + '?ts=' + timestamp + '&sid=' + sid,
type: 'post',
data: JSON.stringify(postData),
dataType: 'json',
cache: false,
success: me.ok,
error: me.notOk
}
);
}
The first callback Function never gets executed, while the second one does get executed but 2 times.
The bug happens on the if (me.mode = 'callback') part of the code.
I already tried other options to make the callback function stuck right.
The first attempt was to store the callback function in the Function scope itself.
with assigning it to this.callback and then trying to access it via me.scope
which did not work. then I tried to access the variables directly.. and it is not helping either...
this.callback = callback;
this.callbackFail = callbackFail;
var me = this;
me.backHandler = function (data) {
if (data)
if (data.responseJSON || data.debug) {
if (data.debug)
var debug = data.debug;
else if (data.responseJSON && data.responseJSON.debug)
var debug = data.responseJSON.debug;
if (window.console) {
for (var key in debug) {
if (debug.hasOwnProperty(key)) {
// console.log(debug[key]);
}
}
}
}
me[me.mode](data);
};
I'm on my wit's end.
First of, callBackFail is never defined in your code.
function AjaxHandlerByClass(className, postData, callback, callbackFail)
You pass in three parameters: className, postData and callback.
AjaxHandlerByClass('url', {clientName: this.clientName}, function (response) { this code gets never called})
Second, this line should be me.mode === 'callback', not me.mode = 'callback'
if (me.mode === 'callback') {
callback(data);
} else {
callbackFail(data);
}
You've named your function AjaxHandlerByClass, I assume you want to use it as a class. You've declared it as function. Regular functions are executed when they are invoked(called) causing the second call to AjaxHandlerByClass() to render twice. To solve your problem you could either create a new instance of your AjaxHandlerByClass using the new keyword.
const firstRequst = new AjaxHandlerByClass('url', {clientName: "https://swapi.co/api/people/"}, successCallback, failCallback);
const secondRequst = new AjaxHandlerByClass('url', {clientName: "https://swapi.co/api/planets/"}, successCallback, failCallback);
Or if you want to wait for the first request to finish before calling the second request you could implement Promise. More on Promise here.
I created a js-fiddle here with some modifications(swapped api and renamed some varaibles just for testing purpose.). One of the ajax-request is successful and the other fails. The result is visible in the developer-console. Note this fiddle is not perfectly written, its just some dummy code for demo purpose.

why am I getting undefined at the moment when I click my button?

I want to try to display my notification json through ajax, but however when I try first show me undefined, and then show me my json what am I doing wrong?
$(function (doc, win, $) {
var notification = win.Notification || win.mozNotification || win.webkitNotification;
var $badge = $("#notifications-badge");
var $list = $("#notifications-list");
var $button = $("#notifications-button");
URL_GET_NOTIFICATION = BASE_URL + 'notifications/getNotification';
function check_notifications() {
$.ajax({
type: 'GET',
url: URL_GET_NOTIFICATION,
//data: { timestamp : timestamp },
dataType: 'json',
async: true,
success: function (data) {
console.log(data);
}
});
}
$button.click(function (e) {
alert(check_notifications());
});
}(document, window, jQuery));
All functions return undefined by default when called, unless something else is specified.
You'd get the same with just
function go() {};
alert( go() ); // undefined
And that's basically what you're doing, alerting a function that doesn't return anything.
If you return something from the function, it works
function go() { return 'Hello Kitty' };
alert( go() ); // Hello Kitty
But, as you're using ajax inside the function, you can't really return the result from that, as it's asynchronous and executes some time after the result is returned.
You'd have to use a callback or promise to make it work.
function check_notifications() {
return $.ajax({
type: 'GET',
url: URL_GET_NOTIFICATION,
//data: { timestamp : timestamp },
dataType: 'json'
});
}
$button.click(function (e) {
check_notifications().done(function(data) {
alert(data);
});
});
As a sidenote, use the console when debugging, not alerts.

Javascript object counter not incrementing as expected

I am having trouble getting the errorCount property to increase during code execution. The problem I am having is occurring inside of the $.ajax request, more specifically the addError() method.
If I use the following code below to check the current count of errorCount it always returns 0 even though I have manually created an error to occur. But inside of the ajax method after I call addError() and then check the value of errorCount it shows 1 like it should. What did I do wrong?
var boom = new test(settings, formData, search);
console.log(boom.errorCount);
boom.queueCalls(settings);
console.log(boom);
console.log(boom.errorCount);
Here is the object code:
function test(a, b, c) {
this.settings = a;
this.formData = b;
this.search = c;
this.errorCount = 0;
}
test.prototype = {
constructor: test,
queueEmails:function(settings, formData, search) {
var url = '/example-url-endpoint';
var data = {postData: settings + "&" + formData + "&" + search};
this.sendRequest(url, data);
},
queueCalls:function(settings) {
var url = '/example-url-endpoint2';
this.sendRequest(url, settings);
},
addMessage:function(response) {
flashMessage(response.Message, response.Result);
},
addError:function() {
this.errorCount++;
},
sendRequest:function(url, data) {
var blah = this;
j$.ajax({
type: "POST",
url: url,
data: data,
dataType: 'json',
success: function(data) {
response = JSON.parse(data);
if(response.Result != 'error') {
blah.addMessage(response);
} else {
blah.addMessage(response);
blah.addError();
console.log(blah.errorCount);
}
},
error: function(e, textStatus, errorThrown) {
blah.addError();
console.log(blah.errorCount);
alert("There was an error creating the queue");
}
});
}
}
The problem is you are doing an asynchronous (AJAX) call. When you call the queueCalls function, it makes the AJAX call, then runs your console.log statements. It does not wait until the AJAX call is done, and you have received your errors to run the console statements. If you want to do that, look at the jQuery documentation for .ajax(), and either make your AJAX call not asynchronous, or put your console statements in a .done() event handler that will fire after the AJAX call is complete.

Parse XML catch block not catching exception in JS

I have a function that takes an XML file (obtained via AJAX) as input, parses it as XML and then execute some functions on it. A stripped down version can be found below.
AJAX
$.ajax({
type: "GET",
url: "./default.xml",
dataType: "xml",
success: function(data) {
parseMech(data);
}
});
parseMech function
function parseMech(xml) {
try {
var xmlObject = $(xml);
// See the output function below
$(".tree.base").html(treeBuilder(xmlObject.find("node").first()));
console.log("succes?");
} catch(e) {
$("#error-msg > .the-msg").text(" Invalid XML structure").parent().fadeIn(250);
console.log("Failed");
}
}
treeBuilder function
function treeBuilder(nodes) {
var newList = $("<ol>");
nodes.each(function (x, e) {
var newItem = $('<li> </li>');
for (var i = 0, l = e.attributes.length, a = null; i < l; i++) {
// Don't forget to add properties as data-attributes
a = e.attributes[i];
newItem.attr("data-" + a.nodeName, a.value);
if (a.nodeName == "cat" || a.nodeName == "word") {
newItem.html('' + a.value + '');
}
}
if ($(this).children('node').length) {
newItem.append(output($(this).children('node')));
}
newList.append(newItem);
});
return newList;
}
This works as it should when default.xml is a valid xml file. However, when it's not (for instance when I leave out a closing tag) the catch blok is not executed. In other words: when executing all functions with an invalid XML as source, neither console logs are executed, even though you would expect at least one (in try or in catch) to be logged.
Am I missing something here?
You need a fail handler in your ajax call.
According to the docs, a jquery ajax call with a dataType of xml returns a xml doc, so the data stream is being parsed in the course of the ajax call.
Alter the ajax call as follows (behaviour verified):
//...
error: function() {
console.log("ajax failed!");
},
//...
Note
Consider to change the way you specify your handlers,as error and success attributes are deprecated:
top.$.ajax({
type: "GET",
url: url,
crossDomain: true,
dataType: "xml",
})
.fail ( function() {
console.log("ajax failed!");
})
.done ( function(data) {
console.log("ajax ok!");
parseMech(data);
});

Callback with javascript and jquery

I am more of a java developer and am having difficulty with javascript callback. I am wondering if any experts here would help me out of my struggle with this code.
I am trying to pull our locations from db and populating in an array. On first load i am trying to refresh all locations and I am having trouble to control the flow of execution and loading values. Below is the code and I have put in the output at the end.
JQUERY CODE:
// load all locations on first load.
refreshLocations();
$("#locInput").autocomplete({source: locationData});
}); // end of document.ready
// function to refresh all locations.
function refreshLocations() {
getLocationArray(function(){
console.log("firing after getting location array");
});
}
// function to get the required array of locations.
function getLocationArray() {
getJsonValues("GET", "getLocalityData.php", "", getLocalityFromJson);
}
// function to pick up localities from json.
function getLocalityFromJson(json){
if (!json) {
console.log("====> JSON IS NOT DEFINED !! <====");
return;
} else {
console.log("json is defined so processing...");
var i = 0;
$.each(json.listinginfo, function() {
var loc = json.listinginfo[i].locality;
locationArray[i] = loc;
console.log("added location ->" + locationArray[i]);
i++;
});
}
//return locationArray;
}
// function to get raw json from db.
function getJsonValues(type, url, query, getLocalityFromJson) {
var json;
// if the previous request is still pending abort.
if (req !== null)
req.abort();
var searchString = "";
if (query !== "") {
searchString = "searchStr" + query;
}
console.log("searchString : (" + query + ")");
req = $.ajax({
type: type,
url: url,
data: searchString,
contentType: "application/json; charset=utf-8",
dataType: "text",
success: function(result) {
json = JSON.parse(result);
console.log("========start of json
return============");
console.log(JSON.stringify(json));
console.log("========end of json
return============");
//return json;
}
});
getLocalityFromJson(json);
return json;
}
the output from above code is as follows:
searchString : () (18:25:36:473)
at locality1.php:74
====> JSON IS NOT DEFINED !! <==== (18:25:36:518)
at locality1.php:48
========start of json return============ (18:25:37:606)
at locality1.php:83
{"listinginfo":[{"listing":"1","locality":"birmingham"},
{"listing":"2","locality":"oxford"}]} (18:25:37:624)
at locality1.php:84
========end of json return============ (18:25:37:642)
at locality1.php:85
>
Help will be greatly appreciated.
call getLocalityFromJson(json); inside your success callback
function getJsonValues(type, url, query, getLocalityFromJson) {
var json;
// if the previous request is still pending abort.
if (req !== null)
req.abort();
var searchString = "";
if (query !== "") {
searchString = "searchStr" + query;
}
console.log("searchString : (" + query + ")");
req = $.ajax({
type: type,
url: url,
data: searchString,
contentType: "application/json; charset=utf-8",
dataType: "text",
success: function(result) {
json = JSON.parse(result);
console.log("========start of json return============");
console.log(JSON.stringify(json));
console.log("========end of json return============");
//return json;
getLocalityFromJson(json);
}
});
}
You need to call getLocalityFromJson(json) and return json inside your ajax success function. Ajax requests are asynchronous, there's no guarantee that the request will be finished by the time you get to the lines getLocalityFromJson(json); return(json); where they are currently.
The call back functions from a jquery ajax call is complete, failure, success, etc..
Success is called after a request is successful,
Failure is called if theres something like an error 500, or a 404, or w/e.
Complete is Always called after a ajax call.
If you want your code to just follow sequence like in java, throw async: false into your ajax call.. but I wouldnt' recommend this as it defeats the purpose of using this method, and also locks up your browser.
You should make sure you are waiting for the request to finish before moving on - so put code in the success function that you want to run AFTER the request has finished fetching your data.
I think you need to remember Ajax is running async, so you need to follow this thread to execute your refresh.

Categories