how to handle ajax parsererror nicely? - javascript

I have a google ad project which requires me to get multiple "setTargeting('', '');" from an object array on json file (via url) --> {"country": "Netherlands", "city": "Amsterdam" }. So far everything works; however, suppose the network fails, or requested JSON parse failed, etc - I'd like to pass an empty array to make sure that the slot will still show ads with no targeting.
What would be a good practise for it?
Advertisements.cachedCategoriesByUrl = {};
Advertisements.getCategories = function(categoriesUrl) {
var cachedCategories = Advertisements.cachedCategoriesByUrl[categoriesUrl];
if(cachedCategories){
return cachedCategories;
} else {
var getCategories = $.ajax({
url: categoriesUrl,
data: { format: 'json' },
error: function(jqXHR, status, thrownError) {
=> I'd like to pass an empty array so the slot will show
ads with no targetting set.
However this doesn't seem to be working.
Do I need to do callback?
}
});
Advertisements.cachedCategoriesByUrl[categoriesUrl] = getCategories;
return getCategories;
}
}
Note:
return getCategories runs before the ajax call finishes. How do I make sure that return getCategories gets my error update(I want to pass an empty array if JSON request fails or invalid). Sorry I am in the learning process.

Solved it with this:
$.ajax({
url: ad.categoriesUrl
}).then(function(data){
Advertisements.advertisementSlot(ad, data);
}, function(data){
data = {};
Advertisements.advertisementSlot(ad, data);
});

Related

Trying to make an AJAX call asynchronous in Javascript

I am trying to retrieve some data from neo4j for my web app. I have my code structured in the following manner:
When I click the button to retrieve the data, call
var childNodes = getAllChildNodes(uuid, ""); //uuid: node specific id in neo4j, second param not important
//do something with childNodes
....
In getAllChildNodes(),
function getAllChildNodes(uuid, filter) {
/*
prepare json data to send
*/
var resultNodes = {}
var successFunction = function(data) {
//store data in resultNodes ...
//do something with the data ...
}
var failFunction = function(xhr, status, error) {
//if query fails
};
//call to API function
try {
getChildrenAPI(jsonData, successFunction, failFunction)
} catch (err) { console.log(err) }
return resultNodes
}
In getChildrenAPI
function getChildrenAPI(jsonData, doneFunction, failFunction) {
var request = $.ajax({
method : 'POST',
url: myurl,
data : JSON.stringify(jsonData),
dataType : 'json',
contentType : 'application/json',
cache : false,
async : true,
});
request.done(function (data) {
doneFunction(data)
})
request.fail(function (xhr, status, error) {
failFunction( xhr, status, error );
});
}
The problem is that my childNodes var does not get populated. When I inspected further, in my getAllChildNodes() function, resultNodes is returned before the query data is stored in successFunction(). I thought this would be an async issue, so I made sure to check that the AJAX call had its async property set to true, but that didn't solve it. So I tried using async await on my getAllChildNodes(), but that didn't work either. So my question is, what am I doing wrong here? I'm still new to the idea of async so this was the best I can do. If someone can please help me with this I would really appreciate it.
It seems that you misunderstood the problem. AJAX requests are asynchronous by default. What you want, as far as I can tell by seeing your code is to be able to use the result of the request after the request in the code. For that you need to make it synchronous. You can specify async to be true, you can await and so on. However, it's a terrible idea in most cases to make your requests asynchronous. If you synchronize your request, then nothing else will run and your page will hang while you await.
What if a request lasts for 10 seconds? In that case your page is unresponsive for ten seconds if you synchronize the request.
What if you send 100 requests and on average they take 1 second? Then your page hangs for 100 seconds.
The best practice is to avoid syncrhonising your requests whenever possible and only do so when absolutely necessary. Instead, you will need to get used to callbacks, that is, functions defined to be executed once the request is completed and define the post-request behavior in them. You could also use promises or web workers, depending on your exact situation.
async function getAllChildNodes(uuid, filter) {
/*
prepare json data to send
*/
var resultNodes = {}
var successFunction = function(data) {
//store data in resultNodes ...
//do something with the data ...
}
var failFunction = function(error) {
//if query fails
};
//call to API function
try {
var data = await $.ajax({
method : 'POST',
url: myurl,
data : JSON.stringify(jsonData),
dataType : 'json',
contentType : 'application/json',
cache : false,
async : true,
});
successFunction(data);
} catch (err) {
console.log(err);
failFunction(err);
}
return resultNodes
}
var childNodes = getAllChildNodes(uuid, "");
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script>
Javascript is single-threaded & non-blocking language so it will not execute code asynchronously.
To make your code sync, you have to create an async function that manage the async code (ajax, timeout, read a file, ...)
I think you're looking for something like the following:
getAllChildNodes(uuid, "", function done(results) {
// Results populated by the done callback.
console.log(results);
});
The trick here is that you need to be keeping track of how many requests were kicked off and when they finished.
So we can then change the definition of getAllChildNodes to call our doneCallback once all requests have been "processed".
function getAllChildNodes(uuid, filter, doneCallback) {
// How many calls do we need to make.
const callsToMake = [1,2,3];
// Track when all calls were made by the results.
const results = [];
const ajaxDoneCallbackCheck = function () {
if (results.length === items.length) {
doneCallback(results);
}
};
const ajaxSuccessCallback = function (data) {
results.push(data);
ajaxDoneCallbackCheck();
};
const ajaxFailCallback = function (error) {
results.push(error);
ajaxDoneCallbackCheck();
}
// Iterate through ajax calls to make.
for (const callToMake of callsToMake) {
// Do ajax stuff.
console.log('Request data');
getChildrenAPI(ajaxSuccessCallback, ajaxFailCallback);
}
}
Now results needs to be processed in our original done callback like so:
getAllChildNodes(uuid, "", function done(results) {
// Results populated by the done callback.
console.log(results);
// Iterate results.
for (const result of results) {
if (result instanceof Error) {
console.error(result);
} else {
// Process or track result!
console.log(result);
}
}
});

Can Mockjax handle single IDs Api from Json file

I'm using Mockjax for the first time to mock a Restful API which will return a series of data given an id. Right now i have a json file that has several Items, and i would like to have a function inside Mockjax (or where necessary) to return only the queried ID. how can I achieve this?
current code :
$.mockjax({
url: "/Api/Cases/{caseId}",
proxy: "/mocks/cases nuevo.json",
dataType: 'json',
responseTime: [500, 800]
});
$.ajax({
type: 'GET',
url: '/Api/Cases/',
data: {caseId: taskId},
success: function(data){
//use the returned
console.log(data);
}
});
current error:
GET http://localhost:8080/Api/Cases/?caseId=100 404 (Not Found)
Great question... yes, you can do this. But you'll have to write the functionality yourself using the response callback function and then making a "real" Ajax request for the file (instead of using the proxy option). Below I just make another $.ajax() call and since I have no mock handler setup for that endpoint, Mockjax lets it go through.
Note that setting up URL params is a little different than you suggest, here is what the mock setup looks like:
$.mockjax({
url: /\/Api\/Cases\/(\d+)/, // notice the regex here to allow for any ID
urlParams: ['caseID'], // This defines the first matching group as "caseID"
responseTime: [500, 800],
response: function(settings, mockDone) {
// hold onto the mock response object
var respObj = this;
// get the mock data file
$.ajax({
url: 'mocks/test-data.json',
success: function(data) {
respObj.status = 200;
// We can now use "caseID" off of the mock settings.urlParams object
respObj.responseText = data[settings.urlParams.caseID];
mockDone();
},
error: function() {
respObj.status = 500;
respObj.responseText = 'Error retrieving mock data';
mockDone();
}
});
}
});
There is one other problem with your code however, your Ajax call does not add the ID to the URL, it adds it to the query string. If you want to use that API endpoint you'll need to change your source code $.ajax() call as well. Here is the new Ajax call:
$.ajax({
type: 'GET',
url: '/Api/Cases/' + taskId, // this will add the ID to the URL
// data: {caseId: taskId}, // this adds the data to the query string
success: function(data){
//use the returned
console.log(data);
}
});
Note that this presumes the mock data is something like:
{
"13": { "name": "Jordan", "level": 21, "id": 13 },
"27": { "name": "Random Guy", "level": 20, "id": 27 }
}
What I have ended up doing, is: I have left the $.mockjax function untouched, and i have manipulated the data inside the ajax request, using jquery's $.grep function as follows:
$.ajax({
type: 'GET',
url: '/Api/Cases/' + taskId,
success: function(data){
//note you have to parse the data as it is received as string
data = JSON.parse(data);
var result = $.grep(data, function(e){ return e.caseId == taskId; });
//since i'm expecting only one result, i pull out the result on the 0 index position
requestedData = result[0];
}
});
The $.grep() method removes items from an array as necessary so that all remaining items pass a provided test see Jquery API, And since our test is that the caseId attribute of the element equals to the taksId variable sent, it will return all the elements that match the given Id, in this case, only one, this is why I've taken only the result on the 0 index position requestedData = result[0];
**Note: **
A more suited solution would be a mixture between what i've done and #jakerella 's answer, since their method implements the find element method inside the mockjacx function, and my function presumes a usual JSON response:
[{"caseId": 30,"name": "Michael"},{"caseId": 31,"name": "Sara"}]

Array is flattened when it's sent through AJAX jQuery request

I have the following endpoint written in Express, using the body-parser middleware.
app.post("/api/poll/new",api.NewPoll);
api.NewPoll = function(req,res){
if(!req.body) return res.status(400).send("MISSING BODY");
console.log(req.body,typeof(req.body));
if(!req.body.name) return res.status(400).send("MISSING NAME");
if(!req.body.options) return res.status(400).send("MISSING OPTIONS");
//rest of the endpoint goes here
};
The data that the endpoint expects looks like this:
{
"name":"Poller",
"options":[
{
"name":"Jojo's Bizarre Adventure",
"desc":"A great show"
},
{
"name":"Bakemonogatari",
"desc":"A real good show"
},
}
When I send this data through Postman, everything works. req.body.options exists and is an array. However, when I do the exact same thing in a jQuery AJAX call, the result is signficantly different:
var payload = {
name:"Poller",
options:g.newPollInfo
//g.newPollInfo contains the same array
}
$.ajax({
method:"POST",
url:"/api/poll/new",
data:payload,
success:function(data){
console.log(data);
},
error:function(req, status, error){
console.log(req,status,error);
}
});
I get a 400 error, reporting missing Options. The printed req.body looks like this:
{ name: 'Poller',
'options[0][name]': 'Jojo'\s Bizarre Adventure',
'options[0][desc]': 'A great show',
'options[1][name]': 'Bakemonogatari',
'options[1][desc]': 'A real good show' } 'object'
I have never had this problem before. The problem is not in express, as a request through Postman using the same data and it works. The only problem I can think of lies in the fact that the request is made from an iframe serviced through a secure connection, but that doesn't make sense.
I have no idea what causes this error.
According to both these questions, the problem is solved specify the header type on the AJAX Request and stringify.
$.ajax({
method:"POST",
url:"/api/poll/new",
data:JSON.stringify(payload),
contentType:"application/json",
success:function(data){
console.log(data);
},
error:function(req, status, error){
console.log(req,status,error);
}
});

Parsing response text as key value pairs in an elegant way

Can't seem to find what I'm looking for in searches so this might be a duplicate but I haven't found an original yet sooo....
I have a an ajax call:
$.ajax({
url: "/events/instructor/",
type: 'POST',
data: {
instructorID: $(this).attr("id")
},
complete: function (data) {
$("#name").html(data["responseText"]["name"]);
$("#email").html(data["responseText"]["email"]);
$("#photo").html(data["responseText"]["photo"]);
$("#summary").html(data["responseText"]["summary"]);
$("#url").html(data["responseText"]["url"]);
}
});
The data being returned is encoded in JSON by the server (C#).
Obviously, data["responseText"]["fieldName"] isn't doing the trick. I could do splits and whatnot but that would mean that if the format changes, I'd need to make sure that the code above keeps up with the changed shape of the data.
How can I say something as simple as data["responseText']["fieldName"] to get the value out of that key?
i think you need to parse json first. look at the api.jquery.com/jquery.parsejson
// data = '{ "name": "John" }'
var obj = jQuery.parseJSON( data );
console.log( obj.name);
// result will be "John"
P.S. also better use 'succes' instead 'complete', you can read about this here Difference between .success() and .complete()?
success: function(data) {
console.log("response is good", data);
},
error: function (){
console.log("something is went wrong");
}
try using like this:
complete: function (data) {
var data=JSON.parse(data);
$("#name").html(data.responseText.name);
$("#email").html(data.responseText.email);
$("#photo").html(data.responseText.photo);
$("#summary").html(data.responseText.summary);
$("#url").html(data.responseText.url);
}
to get only correct response use success.

Unable to get value from json object

I am trying to get a value from a json object after making an ajax call. Not sure what I am doing wrong it seems straight forward but not able to get the data
The data that comes back looks like this
{"data":"[{\"Id\":3,\"Name\":\"D\\u0027Costa\"}]"}
The code, removed some of the code
.ajax({
type: 'POST',
url: "http://localhost:1448/RegisterDetails/",
dataType: 'json',
data: { "HomeID": self.Id, "Name": $("#txtFamilyName").val()},
success: function (result) {
console.log(result.data); //<== the data show here like above
alert(result.data.Id); //<==nothing show
},
error: function (xhr, ajaxOptions, thrownError) {
}
});
I tried in the Chrome console like this
obj2 = {}
Object {}
obj2 = {"data":"[{\"Id\":3,\"Name\":\"D\\u0027Costa\"}]"}
Object {data: "[{"Id":3,"Name":"D\u0027Costa"}]"}
obj2.data
"[{"Id":3,"Name":"D\u0027Costa"}]"
obj2.data.Id
undefined
obj2.Id
undefined
Update
The line that solved the issue as suggested here is
var retValue = JSON.parse(result.data)[0]
Now I can used
retValue.Name
to get the value
Actually, looking at this, my best guess is that you're missing JSON.parse()
.ajax({
type: 'POST',
url: "http://localhost:1448/RegisterDetails/",
dataType: 'json',
data: { "HomeID": self.Id, "Name": $("#txtFamilyName").val()},
success: function (result) {
var javascriptObject = JSON.parse(result);
console.log(javascriptObject ); //<== the data show here like above
alert(javascriptObject.Id); //<==nothing show
},
error: function (xhr, ajaxOptions, thrownError) {
}
});
I also find that doing ajax requests like this is better:
var result = $.ajax({
url: "someUrl",
data: { some: "data" },
method: "POST/GET"
});
result.done(function (data, result) {
if (result == "success") { // ajax success
var data = JSON.parse(data);
//do something here
}
});
For clarity it just looks better, also copying and pasting into different functions as well is better.
The id property is in the first element of the data-array. So, alert(result.data[0].Id) should give the desired result. Just for the record: there is no such thing as a 'JSON-object'. You can parse a JSON (JavaScript Object Notation) string to a Javascript Object, which [parsing] supposedly is handled by the .ajax method here.
The data field is just a string, you should parse it to a JSON object with JSON.parse(result.data), since data is now an array you will need to need to use an index [0] to have access to the object. Know you will be able to get the Id property.
JSON.parse(result.data)[0].Id

Categories

Resources