jQuery -- nesting ajax calls and using data from each call - wikipedia API - javascript

I am having problems in nesting ajax calls with jQuery to wikipedia api.
The HTML is simple, just an input form and a button:
<input id='search-input' type="text" class="form-control">
<button id="search-button" type="button" class="btn btn-primary">Search</button>
<div id ='outputDiv'></div>
THe search button has an event listener that fires a function that grabs data from wikipedia API:
...
searchBtn.addEventListener('click', searchwiki);
...
function searchwiki(){
let searchTermObjects =[]
let term = inputfield.value;
let titleUrl = search_term(term);
createWikiObject(titleUrl).then(function(){
searchTermObjects.forEach(function(elem){
addExtrctToObj(elem)
})
}).then(function(data){
append_result(searchTermObjects)
})
}
function createWikiObject(titleUrl){
return $.ajax({
type: "GET",
url: titleUrl,
dataType : 'jsonp',
async: true,
error : function(ermsg){
console.log('error in searching',ermsg)
},}).then(function(data){
for(let i = 0; i < data[1].length; i ++){
searchTermObjects.push({
'title': data[1][i].replace(/\s+/g, '_'),
'description': data[2][i],
'url': data[3][i],
})
}; // this for loop should push each result as an object to an array named searchtTermObjects, and i am planning to use this array in the next ajax call to add another property named extract to each object in array
}
);
}
function addExtrctToObj(obj){
console.log(obj)
return $.ajax({
type: "GET",
url: get_text(obj['title']),
dataType : 'jsonp',
async: true,
error : function(ermsg){
console.log('error getting text',ermsg)
}
}).then(function (data){
let pageID = Object.keys(data.query.pages);
if(data.query.pages[pageID].hasOwnProperty('extract')){
obj['extract'] = data.query.pages[pageID].extract;
}
// this function adds the extracted text for each article ,
// the searchTermObjects now looks something like:
/ [{'title':...,'url':...,'description':...,'extract':..},{...}]
})
};
function append_result(termsObjectsArray){
// this function should loop through the searchtermobjects and append leading text for each object in the array to the Output div under the button
for (let i = 0; i < termsObjectsArray.length; i++){
let newDiv = document.createElement('div');
HOWEVER, Object.keys(termsObjectsArray[i]) returns only three keys at this time, and doesn't see the extract key'
console.log(Object.keys(termsObjectsArray[i]))
newDiv.classList.add('wiki-result');
newDiv.innerHTML = termsObjectsArray[i]["extract"];
HERE is where i get error -- the inerHtml of newDiv has value UNDEFINED
outputDiv.appendChild(newDiv);
}
}
// the api calls are formed with these functions:
let base_url = "https://en.wikipedia.org/w/api.php";
function search_term(term) {
let request_url = base_url + "?action=opensearch&search=" + term + "&format=json&callback=?";
return request_url;
}
function get_text(term){
let request_url = base_url + "?action=query&prop=extracts&exintro=&format=json&titles=" + term; // explaintex= returns plaintext, if ommited returns html
return request_url;
}
afetr I console.log(searchTermObjects) i get what i need, the array with objects that have all 4 properties with correct names, but I don't understand why the append_result function doesn't see the 'extract' key.
Next to the logged object in the console is the 'i' sign that says 'Value below was evaluated just now' , and there I have what I wanted -- every search result as an object with title, url, description, and extract keys.
copy this code to your IDE to see if you can help me with finding solution.

I believe the issue you're having is that you're attempting to return a Deferred object, and there's nothing to return yet because of the deferral.
return $.ajax({
type: "GET",
url: get_text(obj['title']),
dataType : 'jsonp',
async: true,
error : function(ermsg){
console.log('error getting text',ermsg)
}
})
The async value is true, so the code is moving on before the request is finished, and you're getting a null value back.
Try setting async: false and see if you get a better response. As pointed out by Andrew Lohr in the comments, this is not a good way to solve the problem, it will only tell you if that is the problem.
If it is, then I would recommend not breaking the request up into multiple functions. You should just chain the AJAX calls, using the deferral approach. It would be structured like this:
$.ajax({ ... }).then(function(data){
// ... do something with the data ...
// Make your followup request.
$.ajax({ ... }).then(function(data) {
// ... finalize the response ...
});
});
Also consider using the context option in the ajax call to pass in a callback method that can be fired once the chain is complete.

Related

How to access 'Object' portion of JSON using Jquery?

I used console.table(someData) to output the object shows in the attaches image.
I used the following code to get the data:
var someData = GetJson('someurlthatreturnsjson');
function GetJson(Url) {
return $.ajax({
url: Url,
xhrFields: {
withCredentials: true
},
dataType: "json"
});
}
I tried:
var x = someData.readyState; // 1 was returned as expected.
var y = someData.Object; // undefined.
...so...
var z = someData.Object.responseJSON; // also undefined?
So how would I access elements within the Object portion of this json? Am I missing something?
As you return the $.ajax() call from getJSON(), the someData variable will contain the Deferred object containing the reference to the AJAX call.
To retrieve the response from that call from the Deferred object you can use any of the methods outlined in the documentation I linked to. I would suggest using then() in this case, as the handler function you define will receive the response as the first argument to the function, like this:
var someData = GetJson('someurlthatreturnsjson').then(response => {
// do something with the response here...
console.dir(response);
});
function GetJson(Url) {
return $.ajax({
url: Url,
xhrFields: {
withCredentials: true
},
dataType: "json"
});
}

Updating a list with ajax response data in a specific order

I have an ajax request that gets called several times based on the number of request objects in an array. The order in which these objects are in inside of the array is important, and needs to be reflected in a dynamically generated list in that same order. When the server sends back each response I update a <ul> as shown below.
$.ajax({
type: 'POST',
url: baseServiceURL + 'report/',
processData: false,
dataType: 'json',
contentType: 'application/json',
data: payload,
crossDomain: true,
})
.done(function (response) {
updateUI(response);
})
.fail(function (jqXHR, textStatus) {
// handle failure
});
var updateUI = function (response) {
// Update the drop-down list
$('#dropdown').append('<li><a class="dd-option" data-value="' + response.ReportName + '" data-path="' + response.ReturnURL + '" href="#">' + response.ReportName + '</a></li>');
// do more stuf...
};
How can I dynamically build the list in such a way to where the response display in the proper order? One thing I have done is add a order param to the request who's value is the index of the request object in the array. My thought is my service can send that value back in the response so the javascript can act on it.
EDIT: The question here is asking basically the same thing except rather than using a getJSON command and appending divs I'm using a post and appending <li> elements.
There are two possible strategies here.
Update your UI immediately upon receiving response and then re-render if a new value is received
Wait until all ajax replies have finished and then render your UI
For (1) you should just keep a running total of all items
var $dropdown = $('#dropdown');
var renderDropdown = function(reports) {
//use lodash or underscore.js here cause implementing this manually is annoying
var sortedSelections = _.sortBy(reports, 'order');
var htmlPerItem = sortedSelections.map(function(item) {
return '<li><a ..... </li>';
});
$dropdown.html(htmlPerItem.join(''));
}
var reportSelections = [];
payloads.map(function(payload) {
$.ajax({ ... })
.then(function(response) {
reportSelections.push(response);
renderDropdown(reportSelections);
})
})
for (2) you can use jquery $.when
var gettingResults = payloads.map(function(payload) {
return $.ajax({ .... });
});
$.when(gettingResults).then(function() {
//the first arg will be response1, the second response2, etc
var reportSelections = _.sortBy(arguments, 'order');
renderDropdown(reportSelections);
});
Note in (1) you render once per item but get an updating view as items come in. In (2) you render only once but have to wait until all loading is complete.
Of course a variation of (1) is that you don't re-render anything, but merely insert items into the correct location as they are loaded. That's going to be more difficult to debug and more code so I leave it as an exercise for the reader (use jquery's $.fn.data to store the original item with the element).

In Javascript, process list synchronously

I have a given collection of items to be processed; each item must wait for the completion of the previous one.
By collection of items I mean an array of integer values.
By "processing" I mean make a POST to a HTTP server, passing the integer value of each array element.
I've found something that looks like waht I'm looking for: doSynchronousLoop.js but I wonder if there are alternatives.
If your site may pause rendering while doing the requests, here's a solution with jQuery:
// process 5 items
for (var i = 0; i< 5; i++) {
// ajax request done with jquery
$.ajax({
async: false, /* this makes it execute synchronously */
url: "the url to handle item #i",
type: "POST",
success: function(msg) {
// process data for item #i
}
})
}
Edit: you can solve it asynchronously, too:
items = [put your items here]
current_item = 0
function processItem() {
if (current_item == items.length) {
// list processing finished
return;
}
$.ajax({
async: true,
url: "the url to handle item #current_item",
type: "POST",
success: function(msg) {
// process data for item #current_item
processItem();
current_item++;
}
})
}
Don't miss to put the variables in a scope, I just left them in global scope to make the example easier to understand.
See also the docs: jQuery.ajax

get a callback function to add to object javascript

I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}

How to set values to array when async webservice responce is called

Friends,
I have declared array in javascipt
var Answer1 = new Array(50);
I want to call webserivce using $ajax & i want to store its response at appropriate index of array.
& want to use that array immediately after all the values are set.
Currently i am doing this by using async:false property of $ajax .
Does anyone know way with asynchrnous way because when i use asynchronous values of array remains undefined.
for(var j=0;j < mycollection.length-1;j++)
{
$.ajax({
type: 'GET',
url: webserviceURL,
dataType: 'json',
error: function(data)
{
//alert(data.error);
},
success: function(data)
{
if(data.error!=null)
{
console.log('data error');
Answer1[j] = data.name;
}
},
complete: function(data)
{
alert('completed:');
},
data: {},
async: false
});
Well you are using the wrong index for Answer1:
Answer1[i] = data.name;
should be:
Answer1[j] = data.name;
But if that still doesn't work, pass j as a parameter to your webservice and get the webservice to return it as part of the response so you know the index to assign to.
Also you are only assigning if data.error is not null? Is that what you want, didn't you want to assign if there is no error (i.e. data.error is null)?
Put whatever code uses the array into a function. Call that function from the success handler for your Ajax call.

Categories