output of api callback to show data of the first object - javascript

I am performing an api call back in a loop to get the latest status of a value.. The api call and loop is working but its not showing me the data of the first object returned.. instead it is showing me the data of the last object. The reason for the loop is because there could be multiple objects returned but i want the output to go through them in order from object 0 then object 1 and so on..
Here is a screenshot from firebug showing you two objects with there respective data points. As you can see object 0 is shown first then object 1.
Here is my code to output the data on the page. This code is within a if statement where status = "RESULT" - you can't tell from the below code but both of these objects match that criteria
for (var i = 0; i < response.endpoints.length; i++) {
var endpoint = response.endpoints[i];
//console.log(endpoint);
$pending0.html("<br><b>Server Name: </b>" + endpoint.serverName + "<br><b>Status: </b>" + endpoint.statusMessage + "<br><b>Progress: </b>" + endpoint.statusDetailsMessage);
My issue with the above code is with the order of the output. It shows data for the second object where as I need it to give me the output for the first object.
-- UPDATE --
seems to be working per Barmer's suggestion to add an IF within the loop
for (var i = 0; i < response.endpoints.length; i++) {
var endpoint = response.endpoints[i];
if (endpoint.statusMessage == "In progress") {
//console.log(endpoint);
$pending0.html("<br><b>Server Name: </b>" + endpoint.serverName + "<br><b>Status: </b>" + endpoint.statusMessage + "<br><b>Progress: </b>" + endpoint.statusDetailsMessage);
}
}

Test the status in the loop. Since you only want to show the first endpoint that's in progress, you should break out of the loop when you find it.
for (var i = 0; i < response.endpoints.length; i++) {
var endpoint = response.endpoints[i];
if (endpoint.statusMessage == "In progress") {
//console.log(endpoint);
$pending0.html("<br><b>Server Name: </b>" + endpoint.serverName + "<br><b>Status: </b>" + endpoint.statusMessage + "<br><b>Progress: </b>" + endpoint.statusDetailsMessage);
break;
}
}

Related

Assigning a list of labels values generated from a list of objects

I have an ajax call that returns a Serialized JSON string with various keys and values within it, I want to loop through these values and assign each individual key and value to a different label, I already have 8 labels set up. (I am quite new to Javascript so any help or constructive feedback would be greatly appreciated)
Haven't tried much as I am quite new to JavaScript
var obj = response.ret.SearchCriteria;
var resultJSON = obj;
var result = $.parseJSON(resultJSON);
var count = Object.keys(result).length;
for (i = 1; i < count; i++) {
var c = $('#lbl' + [i]);
$.each(result, function(k, v) {
c.text(k + ' is ' + v);
});
};
I have 6 labels and the last item of the JSON array (String) is displayed in each label
I believe your issue is why only last item of JSON array is being displayed in each label.
This is because of c.text(k + ' is ' + v).
Here the existing text content is replaced with every iteration of 'each' loop
Instead, you can consider doing this, which will append existing content as well with $.each loop.
c.text(c.text() + k + ' is ' + v)
OR
Simply
c.append( k + ' is ' + v)
If I am wrong in my assumption, please describe your scenario more, so that we can help you out :)

Item in function not pushing to array

I have a piece of code in an app that I am having difficulty pushing items to an empty array. At the beginning of this section, I created some empty array variables.
var sumPOP = [];
var sumRACE = [];
var sumLANG = [];
var sumINCOME = [];
I am going to then iterate through some selected data, so I have a for loop. Within this loop, I am making a call to an api (I know, it's GIS. That's irrelevant. Just pretend it's an ajax call) to retrieve some data. I am able to console.log() the data and it shows up correctly. I then want to push that data (each item in the loop) to the before mentioned empty arrays. Then to test that the array has been populated, I console.log() the array, both within the loop and outside it. My problem is that nothing shows when I console.log the array. Why is the data not getting pushed outside the array? Note: console.log(sumPOP) run within the call function(esriRequest) does show the items pushed to the array:
for (var i=0;i<results.features.length;i++){
...
esriRequest({
url:"https://api.census.gov/data/2016/acs/acs5",
content:{
get: 'NAME,B01003_001E,B02001_001E,B06007_001E,B06010_001E',
for: `tract:${ACS_TRCT}`,
in: [`state:${ACS_ST}`,`county:${ACS_CNTY}`]
},
handleAs:'json',
timeout:15000
}).then(function(resp){
result = resp[1];
POP = result[1];
console.log(POP);
sumPOP.push(POP);
RACE = result[2];
LANG = result[3];
INCOME = result[4];
console.log('POP: ' + POP + ', RACE: ' + RACE + ', LANG: '+ LANG + ', INCOME: ' + INCOME);
}, function(error){
alert("Data failed" + error.message);
});
console.log('POP: ' + sumPOP);
...
}
console.log('POP: ' + sumPOP);
Additional information: My eventual goal is to get the final array after the selected data has been iterated through and summarize it; or rather, add it together. My expected array results would be sumPOP = [143, 0, 29, 546, 99];
I want apply a function (also outside the loop) to do this:
newSum = function(category) {
let nAn = n => isNaN(n) ? 0 : n; //control for nonNumbers
return category.reduce((a, b) => nAn(a) + nAn(b))
};
...and then run popTotal = newSum(sumPOP); to get the total.
I believe your data is being pushed, it just appears that it isn't due to the placement of your console.log()'s
Since you are dealing with an async api call, the only place where you are guaranteed to have data is inside your .then() function. Essentially, as you debug, if you add breakpoints, at all your console.log's, you will notice that it hits the ones outside the .then() first and the ones inside the .then() last. Because of that ordering, it will appear that your arrays did not get data pushed to them.
I added some comments to your example code below to illustrate where you should expect to see data.
EDIT: also I made a small adjustment so all the arrays would get populated
EDIT 2: modified the code so it handles multiple async promises in a "synchronous" manner
var sumPOP = [];
var sumRACE = [];
var sumLANG = [];
var sumINCOME = [];
var myPromises = []; // added this new array for promise.all
for (var i = 0; i < results.features.length; i++) {
var myPromise = esriRequest({
url: "https://api.census.gov/data/2016/acs/acs5",
content: {
get: 'NAME,B01003_001E,B02001_001E,B06007_001E,B06010_001E',
for: `tract:${ACS_TRCT}`,
in: [`state:${ACS_ST}`, `county:${ACS_CNTY}`]
},
handleAs: 'json',
timeout: 15000
});
myPromises.push(myPromise);
// because you are making an async request, at this point, sumPOP may be empty
console.log('POP: ' + sumPOP);
}
Promise.all(myPromises).then(function(resp) {
result = resp[1];
POP = result[1];
console.log(POP); // this will show POP with data
RACE = result[2];
LANG = result[3];
INCOME = result[4];
sumPOP.push(POP);
sumRACE.push(RACE); // added this to populate array
sumLANG.push(LANG); // added this to populate array
sumINCOME.push(INCOME); // added this to populate array
// at this point, all your arrays should have data
console.log('POP: ' + POP + ', RACE: ' + RACE + ', LANG: ' + LANG + ', INCOME: ' + INCOME);
// now that this you have all values, you can call your outside function
this.handleData();
}, function(error) {
alert("Data failed" + error.message);
});
// because you are making an async request, at this point, sumPOP may be empty
console.log('POP: ' + sumPOP);
var handleData = function() {
// do something with the completed data
}

Unable to add more than one person to array

The code below is supposed to complete the following tasks once the first and last name fields are entered:
Assign the index number to the person,
Populate that information in a list form
Below is the code that I have so for:
$("volunteerList").value = null;
for(var i = 0, vString = i + 1 + ". " + volunteerArray[i] + "\n"; i < volunteerArray.length; i++){
$("volunteerList").value+=vString;
}
The problem that I am having is that it is not clearing out and no matter what the next name I enter is, it populates the same name as the first entry.
I'm not sure what I am missing from this code to allow for the next person to be entered with the next index number that follows, in this case, either 2, 3, 4, etc.
Any help is greatly appreciated.
You can use the map off of jQuery or the Array to build the list of strings you want to set as the value, and join them on empty string.
var volunteerArray = [ 'Jim', 'Sarah', 'Lance' ];
$("#volunteerList").val($.map(volunteerArray, function(element, index){
return ++index +'. '+ element +'\n';
}).join(''));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="volunteerList"></textarea>
The problem is your loop. You're setting the value for vString during the initialization of the for loop, so it does not get updated each iteration.
$("volunteerList").val() = null;
for(var i = 0; i < volunteerArray.length; i++){
vString = i + 1 + ". " + volunteerArray[i] + "\n"
$("volunteerList").val($("volunteerList").val() + vString);
}
Are you missing an id or class specifier in your jquery?
$(".volunteerList").value =null;
for(var i=0,vString=i+1+". "+volunteerArray[i]+"\n";i< volunteerArray.length;i++){
$(".volunteerList").value+=vString;
}

ajax calls scrambling iterator value

I'm trying to make an AJAX call to the Wikipedia API, looping through results received from a previous call to the Wikipedia API.
var intro = [];
for (var i in json.query.search) {
(function(i) {
$.getJSON("https://en.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&list=&meta=&titles=" + link[i] + "&callback=?&exsentences=1&exintro=1", function(data) {
for (var key in data.query.pages) {
var temp = data.query.pages[key].extract;
intro.push(temp);
break;
}
console.log(intro);
$('#results-div').append("<div class='col-xs-12'><a target='_blank' href='https://en.wikipedia.org/wiki/" + link[i] + "'><div class='result-inner'><h2 class='text-center'>" + pageTitle[i] + "</h2>" + intro[i] + "</div></a></div>");
});
})(i);
}
getJSON does not go through the results in order (the value of i, if called within getJSON's success function, goes in a random order from 0-10, while if it's called outside of it, it will go from 0-10 in order). As a result, the appended values are not in the correct order.
Not only that, the intro array populated by data from getJSON does not always correspond to the values of the link and pageTitle arrays (which correspond to each other). This is the i value used by getJSON isn't the same as the one currently being iterated in the loop. e.g. while i starts at 0, getJSON's first call may use 5 as i.
How can I get getJSON to use the proper iterator value?
I'm not sure you can force getJSON to create an object with keys in a specific order, but you can write your own for loop where you control the order of iteration:
for (var j = 0; j < data.query.pages.length; j++) {
var temp = data.query.pages[j].extract;
intro.push(temp);
}

Optimizing JS Array Search

I am working on a Browser-based media player which is written almost entirely in HTML 5 and JavaScript. The backend is written in PHP but it has one function which is to fill the playlist on the initial load. And the rest is all JS. There is a search bar that refines the playlist. I want it to refine as the person is typing, like most media players do. The only problem with this is that it is very slow and laggy as there are about 1000 songs in the whole program and there is likely to be more as time goes on.
The original playlist load is an ajax call to a PHP page that returns the results as JSON. Each item has 4 attirbutes:
artist
album
file
url
I then loop through each object and add it to an array called playlist. At the end of the looping a copy of playlist is created, backup. This is so that I can refine the playlist variable when people refine their search, but still repopulated it from backup without making another server request.
The method refine() is called when the user types a key into the searchbox. It flushes playlist and searches through each property (not including url) of each object in the backup array for a match in the string. If there is a match in any of the properties, it appends the information to a table that displays the playlist, and adds it to the object to playlist for access by the actual player.
Code for the refine() method:
function refine() {
$('#loadinggif').show();
$('#library').html("<table id='libtable'><tr><th>Artist</th><th>Album</th><th>File</th><th> </th></tr></table>");
playlist = [];
for (var j = 0; j < backup.length; j++) {
var sfile = new String(backup[j].file);
var salbum = new String(backup[j].album);
var sartist = new String(backup[j].artist);
if (sfile.toLowerCase().search($('#search').val().toLowerCase()) !== -1 || salbum.toLowerCase().search($('#search').val().toLowerCase()) !== -1 || sartist.toLowerCase().search($('#search').val().toLowerCase()) !== -1) {
playlist.push(backup[j]);
num = playlist.length-1;
$("<tr></tr>").html("<td>" + num + "</td><td>" + sartist + "</td><td>" + salbum + "</td><td>" + sfile + "</td><td><a href='#' onclick='setplay(" + num +");'>Play</a></td>").appendTo('#libtable');
}
}
$('#loadinggif').hide();
}
As I said before, for the first couple of letters typed, this is very slow and laggy. I am looking for ways to refine this to make it much faster and more smooth.
$('#search') isn't cheap. Move it outside the loop.
Move append() outside the loop. Just accumulate the markup in a string and append it once after the loop.
This should be much faster
function refine() {
$('#loadinggif').show();
$('#library').html("<table id='libtable'><tr><th>Artist</th><th>Album</th><th>File</th><th> </th></tr></table>");
playlist = [];
var srchText = $('#search').val().toLowerCase();
var markup = ["<tbody>"];
for (var j = 0; j < backup.length; j++) {
var sfile = backup[j].file.toLowerCase();
var salbum = backup[j].album.toLowerCase();
var sartist = backup[j].artist.toLowerCase();
if (sfile.search(srchText) !== -1 || salbum.search(srchText) !== -1 || sartist.search(srchText) !== -1) {
playlist.push(backup[j]);
num = playlist.length-1;
markup.push("<tr><td>" + num + "</td><td>" + sartist + "</td><td>" + salbum + "</td><td>" + sfile + "</td><td><a href='#' onclick='setplay(" + num +");'>Play</a></td></tr>");
}
}
markup.push("</tbody>");
$("#libtable").append(markup.join(''));
$('#loadinggif').hide();
}
I would suggest building your playlist information a little differently. You could probably get a pretty decent performance gain just by splitting up your playlist info by first letter.
albums = {
'a': [list of albums starting with a],
'b': ...
}
And doing the same for files and artists, of course.
One thing you could do is to take advantage of jQuery's ability to cache document fragments (the example is from a talk John Resig gave but you could apply it to your code):
// SLOW AS IT IS NOT CACHED. BECAUSE OF FOO
$("ul").append("<li><a>" + foo + "</a></li>");
// FAST. DOCUMENT FRAGMENT IS CACHED
$("<li><a></a></li>")
.find("a").text(foo).end()
.appendTo("ul");
This would be applicable to your line above:
$("<tr></tr>").html("<td>" + num + "</td><td>" + sartist + "</td><td>" + salbum + "</td><td>" + sfile + "</td><td><a href='#' onclick='setplay(" + num +");'>Play</a></td>").appendTo('#libtable');

Categories

Resources