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);
}
Related
Thanks for the answers on the previous two questions. I have a new one, and this one is a collapsible panel in jQuery. The concept is, the first key of a JSON object will appear as a button, and the other keys will be treated as regular text like <p> and the like.
I have this function which tests for the first index of an object.
function isFirstIndex(obj){
var key;
for(key in obj){
if(obj[key]===0){
return true;
}
}
return false;
}
I have tried this one:
function generateTree(data, selId){
var cnt = "";
for (var i=0; i<5; i++){
var row = data[i];
$.each(row, function(key,value){
if (isFirstIndex(row)){
cnt += "<button>" + value + "</button><br/>";
} else{
cnt += "<strong>" + key + "</strong> :" + value + "<br/>";
}
});
cnt += "<br/>";
}
$(selId).html(cnt);
}
But eventually found out in debugging that the key in the isFirstIndex function is compared with a string.
Suppose I have a JSON :
{"userId" : 1, "name" : "cool name"}
I want to show the first key of any JSON set as a button, and the following properties will be ordinary text. Please allow me to post a pseudo-code like process.
Loop through all elements of data response
Loop through each key and value of each data element.
If the key is the first occurrence within the data set
display it as a button.
else
display it as ordinary text.
End Inner Loop
End outer loop
What UtsavShah means is that for (key in obj) may iterate keys in obj in any order, JS spec does not enforce any order.
In fact, JS spec does not enforce any order not only for iteration, but also for internal storage: each JS engine implementation (hence depending on browsers) may store your JSON keys in any order, so even though you write your "userId" first, it does not mean at all that the browser will keep it as the first key. For that, you have to use an Array, or use a convention with a specific key.
The way your code is written, it will look for a key named "0" in your object (row). BTW your i iterator is useless in isFirstIndex function.
What you may try to achieve is to test if the value assigned to "userId" key is equal to 0? In that case, you would simply test if (obj["userId"] === 0).
EDIT: (after you have explained that userId is the one to be a button)
If you just want the value in key "userId" to be displayed as a button, you would simply do:
function generateTree(data, selId){
var cnt = "";
for (var i=0; i<5; i++){
var row = data[i];
$.each(row, function (key,value) { // Note that $.each does not necessarily iterates in any specific order either.
if (key === "userId"){
cnt += "<button>" + value + "</button><br/>";
} else{
cnt += "<strong>" + key + "</strong> :" + value + "<br/>";
}
});
cnt += "<br/>";
}
$(selId).html(cnt);
}
EDIT2:
If you want an order, you need an array. If you want ordered keys, you could shape your data like so (of course this must be implemented in both server and client):
[
{"userId": 1},
{"name": "cool name"}
]
If you just need to know which particular key is specific and should be set as a button, make up a convention with your server and have your data specify which is the specific key, e.g.:
{
"userId": 1,
"name": "cool name",
"specificKeyToBeTransformedIntoAButton": "userId"
}
Im stuck.
I have a button which returns information about a event, name, date and so on.
In the script it looks like this:
for(var i = 0; i < result.length ; i++)
{
var item = result[i];
$("#eventList").append("<h3>" + result.eventDate + "</h3>" + "<br>" + result.eventId + "<br>" + result.description + "<br>");
}
This generates a list of events that goes to a div, alla of the events in one div. But i would like every event to be placed in one separate div/box.
Any ideas?
You can create them inside a div and then append all of them at the end to the dom.
var divs = [];
var $div;
results.forEach(function(item){
$div = $('<div></div>');
$div.append("<h3>" + item.eventDate + "</h3>");
$div.append("<br>"+ item.eventId);
$div.append("<br>"+ item.description);
divs.push($div);
});
$("#eventList").append(divs);
You can create your item variable inside the for loop. When ii gets too big, result[ii] will be undefined or false, and the loop will stop. I prefer to use ii to i, because it's easier to find if I want to search for a repeat loop.
Each jQuery operation returns the jQuery object that it was applied to, so you can chain your operations. You can create an empty element, and then set its text in the next operation, to make the code more compact.
for(var ii=0, item; item=result[ii]; ii++) {
$("#eventList")
.append($("<div>")
.append($("<h3>").text(item.eventDate))
.append($("<p>").text(item.eventId))
.append($("<p>").text(item.description))
)
}
jsFiddle
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;
}
}
I am working with the google sites list item.
The classes are Here and Here
I have been able to iterate through the columns and put all of the column headers in to one array with the following code.
//Global
var page = getPageByUrl(enter URL here)
var name = page.getName();
function getInfo() {
var columns = page.getColumns();
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
}
Now I want to be able to get each row of the listitem and put it in its own array.
I can add the variable
function getInfo() {
var columns = page.getColumns();
var listItems = page.getListItems();//new variable
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
}
Now that I have the variable the output is [ListItem, ListItem, ListItem, ListItem]
So I can use a .length and get a return of 4.
So now I know I have 4 rows of data so based on my wants I need 4 arrays.
Small interjection here, Not a coder by trade but code as a precursor to wants becoming needs.
A buddy of mine who is a JS coder by trade showed me this code which does work. With the logger added by me.
for (var i in listItems) {
if (listItems.hasOwnProperty(i)) {
item = listItems[i];
for (var x = 0; x < columnList.length; x++) {
attrib = item.getValueByName(columnList[x]);
Logger.log("Logging value of get list page get value by name = " + columnList[x] + " " + attrib);
}
}
}
Which brings the total code to
var name = page.getName();
var listItems = page.getListItems();
var listCount = listItems.length
var listList = [];
var columns = page.getColumns();
var name = columns[0].getName();
var item, attrib = 0;
var columnList = [];
Logger.log(listItems);
Logger.log(name + " was last updated " + page.getLastUpdated());
Logger.log(name + " was last edited " + page.getLastEdited());
var listCount = 0;
//Get Column Names
for (var j in columns) {
var cName =columns[j].getName();
columnList.push(cName);
}
Logger.log(columnList);
// Get index of Due Date
var dueDateValue = columnList.indexOf("Due Date");
Logger.log("The index of due date is " + dueDateValue);
for (var i in listItems) {
if (listItems.hasOwnProperty(i)) {
item = listItems[i];
for (var x = 0; x < columnList.length; x++) {
attrib = item.getValueByName(columnList[x]);
Logger.log("Logging value of get list page get value by name = " + columnList[x] + " " + attrib);
}
}
}
}`
Forgive the above code as it has been a bit of a sketch pad trying to work this out.
I am a bit behind on understanding what is happening here
for (var i in items) { // This is for each item in the items array
if (items.hasOwnProperty(i)) {
if items is an array, how can we use has own property? Doesn't that belong to an object? Does an array become an object?
My questions are two category fold.
Category # 1
What is happening with the hasOwnProperty?
-Does the array become an object and thus can be passed to .hasOwnProperty value
Category # 2
Is this the only way to take the values from the listitem and populate an array
- If it is, is there some way to delimit so I can pass each row into it's own array
- If it isn't , why does it work with the hasOwnProperty and why doesn't it work without it in the example below
for (var i in listItems) {
for (var y = 0; y < columnList.length; y++) {
item = listItems[i];
listList = item.getValueByName(columnList[x]);
Logger.log("Logging my version of list naming " + listList);
}
In which I get a "Invalid argument: name (line 41" response. Highlighting the
listList = item.getValueByName(columnList[x]);
Not looking for a handout but I am looking to understand the hasOwnPropertyValue further.
My current understanding is that hasOwnValue has to do with prototyping ( vague understanding ) which doesn't seem to be the case in this instance
and it has to depend on a object which I described by confusion earlier.
To clarify my want:
I would like to have each row of listitems in its own array so I can compare an index value and sort by date as my current column headers are
["Project", "Start Date" , "End Date"]
Any and all help is much appreciated for this JS beginner of 2 weeks.
An array can be inside of an object as the value of a member:
{"myFirstArray":"[one,two,blue]"}
The above object has one member, a name/value pair, where the value of the member is an array.
Here is a link to a website that explains JSON.
Link To JSON.org
JSON explained by Mozilla
There are websites that will test the validity of an object:
Link to JSONLint.com
An array has elements, and elements in an array can be other arrays. So, there can be arrays inside of arrays.
.hasOwnProperty returns either true or false.
Documentation hasOwnProperty
Interestingly, I can use the hasOwnProperty method in Apps Script on an array, without an error being produced:
function testHasProp() {
var anArrayTest = [];
anArrayTest = ['one', 'two', 'blue'];
Logger.log(anArrayTest);
var whatIsTheResult = anArrayTest.hasOwnProperty('one');
Logger.log(whatIsTheResult);
Logger.log(anArrayTest);
}
The result will always be false. Using the hasOwnProperty method on an array doesn't change the array to an object, and it's an incorrect way of using Javascript which is returning false.
You could put your list values an object instead of an array. An advantage to an object is being able to reference a value by it's property name regardless of where the property is indexed. With an array, you need to know what the index number is to retrieve a specific element.
Here is a post that deals with adding properties to an object in JavaScript:
StackOverflow Link
You can either use dot notation:
objName.newProperty = 'newvalue';
or brackets
objName["newProperty"] = 'newvalue';
To add a new name/value pair (property) to an object.
Okay I have a a couple of functions. I don't think most of them are relevant. What I want to do is create an html list when you click a button, and store the value in an array. However I want to be able to update this list without outputting the entire array again. I have it set up to accept the input and I can get it to loop and print the array but it will print the entire array and I only want one. This seems like a common thing but my Google-fu returned nothing.
So I have a list variable that connects to an input, logs it into an array, and another function to clear it and print out the values.
Code snippet:
var listItemInput= document.getElementByID("listItem");
var listItem= [];
function insertListItem(){
listItem.push(listItemInput.value);
clearAndShow();
}
function clearAndShow(){
listItemInput.value= "";
}
function printList{
for (var i = 0; i < listItem.length; i++){
document.getElementById("list").innerHTML += '<li>' + listItem[i] + '</li>';
}
When the printList funciton is called by pressing the button it prints the entire array over however I would like a button that simply prints the newest item. How could I do that?
For clarification, I need to print out the list to html and store the values in an array, the values will later be referenced in an if else argument to combine and print them with new variables.
EDIT:
I plugged in the var = lastIndex and changed it as well as made two more variables for my list. This seems to make it work. Thank you.
You could keep track of the last index printed.
var listItemInput= document.getElementByID("listItem");
var listItem = [];
var lastIndex = 0; //Keep track of the last index shown.
function insertListItem() {
listItem.push(listItemInput.value);
clearAndShow();
}
function clearAndShow() {
listItemInput.value = "";
}
function printList() {
for (; lastIndex < listItem.length; lastIndex++) {
document.getElementById("list").innerHTML += '<li>' + listItem[lastIndex] + '</li>';
}
}
This approach assumes you won't be removing items from listItem array, which you didn't express is something that would be done.
If you only want one element, why do you need to iterate?
function printList() {
document.getElementById('list').innerHTML = '<li>' + listItem[listItem.length-1] + '</li>';
}