Accessing a JSON object from an API with AJAX and JavaScript - javascript

I'm trying to use AJAX for a simple project I am building using a RESTful API. I want get some data from the API which has a list of people and I want to output that list onto a HTML page.
My XHR object seems to work fine because I made it log the string to the console, it's just accessing the data which is in a nested JSON object that is baffling me. I want to loop through the object and get the name of the person and out it as a <li> item.
Here is the JSON file (from http://api.pmg.org.za/member/):
{
count: 505,
results: [
{
bio: "",
pa_link: "/person/xxxxx-xxxxxx/",
house_id: 3,
name: "xxxxxxx",
url: "http://api.pmg.org.za/member/121/",
house: {
name_short: "NA",
id: 3,
name: "xxxxxxx"
},
start_date: "2013-04-09",
current: true,
profile_pic_url: "http://xxxxxxxxxxx.jpg",
party_id: 1,
pa_url: "http://www.xxxxxxxxx/",
party: {
id: 1,
name: "xxx"
},
// more...
},
// more...
]
}
And my script to access the JSON object:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PMG API experimentation</title>
</head>
<body>
<div id="members"></div>
<script type="text/javascript">
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
//console.log(xhr.responseText);
var parlyMembers = JSON.parse(xhr.responseText);
var membersHTML = '<ul class="members">';
for (var i = 0; i < parlyMembers.length; i++) {
membersHTML += '<li>'
membersHTML += parlyMembers.results[i].name;
membersHTML += '</li>'
}
membersHTML += '</ul>';
document.getElementById('members').innerHTML = membersHTML;
};
};
xhr.open('GET', 'http://api.pmg.org.za/member/');
xhr.send();
</script>
</body>
</html>
I have a feeling that my JSON query is wrong somehow. Please help.

You are getting the length from parlyMembers in your for-loop, but looping over parlyMembers.results. You need the check the length of the node you are iterating over.
for (var i = 0; i < parlyMembers.results.length; i++) {
membersHTML += '<li>'
membersHTML += parlyMembers.results[i].name;
membersHTML += '</li>'
}

Your JSON string is not okay, please verify it here and correct it.
http://jsonlint.com/
To access the json data in javascript.
var javascript_object = JSON.parse(json_string);
console.log(javascript_object);
you can see complete object, and you can access the variable accordingly.
Thanks
Amit

Related

AJAX return undefined in html document

I have the following xml document
<?xml version="1.0" ?>
<result searchKeyword="Mathematics">
<video>
<title>Chaos Game</title>
<channel>Numberphile</channel>
<view>428K</view>
<link>http://www.youtube.com/watch?v=kbKtFN71Lfs</link>
<image>http://i.ytimg.com/vi/kbKtFN71Lfs/0.jpg</image>
<length>8:38</length>
</video>
<video>
<title>Australian Story: Meet Eddie Woo, the maths teacher you wish you&apos;d had in high school</title>
<channel>ABC News (Australia)</channel>
<view>223K</view>
<link>http://www.youtube.com/watch?v=SjIHB8WzJek</link>
<image>http://i.ytimg.com/vi/SjIHB8WzJek/0.jpg</image>
<length>28:08</length>
</video>
<video>
<title>Ham Sandwich Problem</title>
<channel>Numberphile</channel>
<view>557K</view>
<link>http://www.youtube.com/watch?v=YCXmUi56rao</link>
<image>http://i.ytimg.com/vi/YCXmUi56rao/0.jpg</image>
<length>5:53</length>
</video>
<video>
<title>Magic Square Party Trick</title>
<channel>Numberphile</channel>
<view>312K</view>
<link>http://www.youtube.com/watch?v=aQxCnmhqZko</link>
<image>http://i.ytimg.com/vi/aQxCnmhqZko/0.jpg</image>
<length>3:57</length>
</video>
<video>
<title>The 8 Queen Problem</title>
<channel>Numberphile</channel>
<view>909K</view>
<link>http://www.youtube.com/watch?v=jPcBU0Z2Hj8</link>
<image>http://i.ytimg.com/vi/jPcBU0Z2Hj8/0.jpg</image>
<length>7:03</length>
</video>
</result>
I have created this html file which has an AJAX call to get the xml file but it return all the values as "undefined"
<html>
<head>
<title>A7-Question2</title>
<script>
function getSearch()
{
// create an XMLHttpRequest
var xhttp = new XMLHttpRequest();
//create a handler for the readyState change
xhttp.onreadystatechange = function() {
readyStateChangeHandler(xhttp);
};
//get XML file by making async call
xhttp.open("GET", "A7.xml", true);
xhttp.send();
}
// handler for the readyState change
function readyStateChangeHandler(xhttp){
if (xhttp.readyState == 4){
// readyState = 4 means DONE
if(xhttp.status == 200){
// status = 200 means OK
handleStatusSuccess(xhttp);
}else{
// status is NOT OK
handleStatusFailure(xhttp);
}
}
}
// XMLHttpRequest failed
function handleStatusFailure(xhttp){
// display error message
var displayDiv = document.getElementById("display");
displayDiv.innerHTML = "XMLHttpRequest failed: status " + xhttp.status;
}
// XMLHttpRequest success
function handleStatusSuccess(xhttp){
var xml = xhttp.responseXML;
// print XML on the console
console.log(xml);
// parse the XML into an object
var searchResult = parseXML(xml);
// print object on the console
console.log(searchResult);
// display the object on the page
display(searchResult);
}
// parse the XML into an object
function parseXML(xml){
var resultElement = xml.getElementsByTagName("result")[0];
//create a receipt object to hold the information in the xml file
var searchResult = {};
searchResult.searchKeyword= resultElement.getAttribute("searchKeyword");
var videoElements = xml.getElementsByTagName("video");
//create an array to hold the items
searchResult.videoArray = [];
for(var i=0; i< videoElements.length; i++){
var video = {};
video.title = videoElements[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
video.channel = Number(videoElements[i].getElementsByTagName("channel")[0].childNodes[0].nodeValue);
video.view = Number(videoElements[i].getElementsByTagName("view")[0].childNodes[0].nodeValue);
video.link = Number(videoElements[i].getElementsByTagName("link")[0].childNodes[0].nodeValue);
video.image = Number(videoElements[i].getElementsByTagName("image")[0].childNodes[0].nodeValue);
searchResult.videoArray.push(video);
};
return searchResult;
}
// display the searcg result object on the page
function display(searchResult){
var html = "<p>searchKeyword: Mathematics</p>";
for(var i=0; i<searchResult.videoArray.length; i++){
var video = searchResult.videoArray[i];
html += "title: " + searchResult.title + "<br/>";
html += "channel: " + searchResult.channel + "<br/>";
html += "view: " + searchResult.view + "<br/>";
html += "link: " + searchResult.link + "<br/>";
html += "image: " + searchResult.image + "<br/>";
html += "length: " + searchResult.length + "<br/>";
}
var displayDiv = document.getElementById("display");
displayDiv.innerHTML = html;
}
</script>
</head>
<body>
<button onclick="getSearch()">Get Search Result</button>
<div id="display"></div>
</body>
</html>
Is the problem with my success function? Is it returning null because it hasn't returned all the values or something due to how AJAX runs?
Thanks heaps for any help
There's a lot of code to go over and a working snippet can't be produced because we can't put the XML file here.
This answer is making an assumption that your response from the XMLHttpRequest is null and the problem does not lie in any of your parsing functions.
It also seems that you're over complicating the request process by passing it around to many functions when it's quite simple itself.
Here is an example I made locally that correctly logged the XML to the console:
<!doctype html>
<html>
<head>
<title>A7-Questions2</title>
</head>
<body>
<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (xhttp.readyState == 4 && xhttp.status == 200) {
var xml = xhttp.responseXML;
// Logs just fine for me. You can do your parsing here.
console.log(xml);
}
};
xhttp.onerror = function() {
// Display error message.
var displayDiv = document.getElementById('display');
displayDiv.textContent = 'XMLHttpRequest failed status: ' + xhttp.status;
};
xhttp.open('GET', './path/to/xml.xml');
xhttp.send();
</script>
</body>
</html>

Load more json data onClick

I have been trying to create a webpage that appends JSON data into a ul. The problem is that the JSON file has more than 600 values.
I would like to limit the number of values retrieved, say 10 and then add a 'load more' button to append more, eg. 10 more, to it and so on. Here's my code.
<body onload="loadUser(20)">
<ul id="placeholder"></ul>
function loadUser(arg) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'people.json', true);
xhr.onload = function() {
if (this.status == 200) {
var users = JSON.parse(this.responseText);
for (var i = 0; i < arg; i++) {
var output = `<li class="list_item">${users[i].name</li>`;
document.getElementById('placeholder').innerHTML += output;
}
document.getElementById('placeholder').innerHTML += '<button onclick="loadmore()">load more</button>';
}
}
xhr.send();
}
// JSON Example:
[{
"id": 1,
"name": "Mithu Mondal",
"email": "mithu#bla.com"
},
{
"id": 2,
"name": "Frankenstien",
"email": "frank#gmail.com"
}
]
Here's the link: https://www.mithuation.ml/jsonExample/
Thanks in Advance.
When you perform an AJAX request (XMLHTTPRequest) it loads the entire file. There is no way to have the browser load a partial file.
If you do not plan to use a database (which would allow you to query a certain number of items at a time), I recommend that you split your data up into several JSON files. When you perform the XMLHTTPRequest, you will only retrieve a subset of the data. For the next request, you will retrieve the next file and thus get the next set of data.
I guess this is what you are searching for Lazy.js. It will parse as much of the JSON as possible, asynchronously.
Import the libraries:
<script type="text/javascript" src="lazy.js"></script>
<!-- optional: if you want support for DOM event and AJAX-based sequences: -->
<script type="text/javascript" src="lazy.browser.js"></script>
If your want to retrieve 10 item at a time:
var response = JSON.parse(this.responseText);
var result = Lazy(response)
.take(10);
document.getElementById('placeholder').innerHTML += output;

How to improve display of JSON data

I am new to JSON and JS, and have generated a JSON file to display data via .onclick event. I have gotten so far as generating the JSON data and displaying it on screen, but now I want to style it in a table format, where the elements are able to be seen more clearly. Any help would be awesome!
Here's my JS:
addEventListener("load", set_up_click_handler);
function set_up_click_handler() {
var url = 'http://localhost/Advanced_Web/Final_Project/data/exhibitions.json';
var button = document.getElementById("button");
button.addEventListener("click", click_handler);
function click_handler(event) {
var request = new XMLHttpRequest();
request.open('GET', url);
request.addEventListener("load", response_handler);
request.send();
};
function response_handler() {
if (this.status == 200) {
var json = this.responseText;
var data = JSON.parse(json);
window.localStorage.setItem('exhibitions', JSON.stringify(data));
var div = document.createElement("div");
div.setAttribute("id", "dateOfExhibition");
var list = $('<ul/>');
for (var item in data) {
list.append(
$("<li />").text(item + ": " + data[item])
);
}
$('#exhibitions').append(list);
} else {
alert('An error has occurred.');
}
}
}
And if anyone is feeling extra charitable today, I'm also having this following issue: every time I click on my button, the list displays itself once again. How do I rework the code so that it only displays itself once?
without really knowing the style of the table required please see the example formatting the data into a table with the headers on display, the address with an empty array also has not been handled in this function
var jsonData = { "id": "Pavlov's Dog", "dateOfExhibition": "2018-07-08T22:00:00.000Z", "address": [], "street": "Bergmannstrasse 29", "city": "Berlin", "country": "Deutschland", "zip": "10473"};
function createTable(jsonData){
//create headers
var head = $("<tr />");
var keys = Object.keys(jsonData);
keys.forEach(function(key){
head.append($("<th>"+ key + "</th>"));
});
$("#exhibitionTable").append(head);
//append data (if you have multiple objects in an array like this wrap this in a forEach)
var row = $("<tr />");
for (var item in jsonData){
row.append($("<td>"+ jsonData[item] + "</td>"));
}
$("#exhibitionTable").append(row);
}
$(document).ready(function(){
createTable(jsonData);
});
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<table id="exhibitionTable">
</table>
</body>
</html>

Listing all posts with Blogger API

I'm trying to list all blog posts with the Blogger API v3:
<script type="text/javascript">
function handleResponse(response) {
var post_number = Object.keys(response.items).length; //number of posts
for (i=0; i<post_number; i++) {
$('#content').append('<div id="post' + (i+1) + '" class="post"><p></p></div>');
$('.post p').html(Object.keys(response.items[i].title));
}
}
</script>
<script src="https://www.googleapis.com/blogger/v3/blogs/1961645108677548855/posts?callback=handleResponse&key=AIzaSyAJESQB3ddltUcDbZif3LUnX-Gzr18tBRg"></script>
This does append 3 divs (because of 3 posts) to my content div. But the content of each of this divs is:
<p>
"1"
"2"
"3"
"4"
"5"
</p>
I have no clue why, though I assume that title is an attribute of items[].
Any solutions or clues?
Thanks for answers!
You should removed Object.keys() and try this:
<script type="text/javascript">
function handleResponse(response) {
var post_number = Object.keys(response.items).length; //number of posts
for (i=0; i<post_number; i++) {
$('#content').append('<div id="post' + (i+1) + '" class="post"><p></p></div>');
$('.post p').html(response.items[i].title);
}
}
</script>
<script src="https://www.googleapis.com/blogger/v3/blogs/1961645108677548855/posts?callback=handleResponse&key=AIzaSyAJESQB3ddltUcDbZif3LUnX-Gzr18tBRg"></script>
In you case you shouldn't use Object.keys()
You request doesn't use the maxResults parameter and limited number of posts is retrieved so I recommend to use Google JavaScript Client Library - Blogger API and recursively retrieve all posts of a blog.
See the following example:
<script>
function renderResults(response) {
if (response.items) {
for (var i = 0; i < response.items.length; i++) {
//do whatever you want with the posts of your blog
}
}
if(response.nextPageToken) {
var blogId = 'XXX Your blogId XXX';
var request = gapi.client.blogger.posts.list({
'blogId': blogId,
'pageToken': response.nextPageToken,
'maxResults': 100,
});
request.execute(renderResults);
}
}
function init() {
gapi.client.setApiKey('XXX Get your API Key from https://code.google.com/apis/console XXX');
gapi.client.load('blogger', 'v3', function() {
var blogId = 'XXX Your blogId XXX';
var request = gapi.client.blogger.posts.list({
'blogId': blogId,
'maxResults': 100,
});
request.execute(renderResults);
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=init"></script>

fetching xml data into a div via ajax and javascript

Building a chat app and I am trying to fetch all logged in user into a div with ID name "chat_members". But nothing shows up in the div and I have verified that the xml file structure is correct but the javascript i'm using alongside ajax isn't just working.
I think the problem is around the area of the code where I'm trying to spool out the xml data in the for loop.
XML data sample:
<member>
<user id="1">Ken Sam</user>
<user id="2">Andy James</user>
</member>
Javascript
<script language="javascript">
// JavaScript Document
var getMember = XmlHttpRequestObject();
var lastMsg = 0;
var mTimer;
function startChat() {
getOnlineMembers();
}
// Checking if XMLHttpRequest object exist in user browser
function XmlHttpRequestObject(){
if(window.XMLHttpRequest){
return new XMLHttpRequest();
}
else if(window.ActiveXObject){
return new ActiveXObject("Microsoft.XMLHTTP");
} else{
//alert("Status: Unable to launch Chat Object. Consider upgrading your browser.");
document.getElementById("ajax_status").innerHTML = "Status: Unable to launch Chat Object. Consider upgrading your browser.";
}
}
function getOnlineMembers(){
if(getMember.readyState == 4 || getMember.readyState == 0){
getMember.open("GET", "get_chat.php?get_member", true);
getMember.onreadystatechange = memberReceivedHandler;
getMember.send(null);
}else{
// if the connection is busy, try again after one second
setTimeout('getOnlineMembers()', 1000);
}
}
function memberReceivedHandler(){
if(getMember.readyState == 4){
if(getMember.status == 200){
var chat_members_div = document.getElementById('chat_members');
var xmldoc = getMember.responseXML;
var members_nodes = xmldoc.getElementsByTagName("member");
var n_members = members_nodes.length;
for (i = 0; i < n_members; i++) {
chat_members_div.innerHTML += '<p>' + members_nodes[i].childNodes.nodeValue + '</p>';
chat_members_div.scrollTop = chat_members_div.scrollHeight;
}
mTimer = setTimeout('getOnlineMembers();',2000); //Refresh our chat members in 2 seconds
}
}
}
</script>
HTML page
<body onLoad="javascript:startChat();">
<!--- START: Div displaying all online members --->
<div id="chat_members">
</div>
<!---END: Div displaying all online members --->
</body>
I'm new to ajax and would really appreciate getting help with this.
Thanks!
To troubleshoot this:
-- Use an HTTP analyzer like HTTP Fiddler. Take a look at the communication -- is your page calling the server and getting the code that you want back, correctly, and not some type of HTTP error?
-- Check your IF statements, and make sure they're bracketed correctly. When I see:
if(getMember.readyState == 4 || getMember.readyState == 0){
I see confusion. It should be:
if( (getMember.readyState == 4) || (getMember.readyState == 0)){
It might not make a difference, but it's good to be absolutely sure.
-- Put some kind of check in your javascript clauses after the IF to make sure program flow is executing properly. If you don't have a debugger, just stick an alert box in there.
You must send the xmlhttp request before checking the response status:
function getOnlineMembers(){
getMember.open("GET", "get_chat.php?get_member", true);
getMember.onreadystatechange = memberReceivedHandler;
getMember.timeout = 1000; //set timeout for xmlhttp request
getMember.ontimeout = memberTimeoutHandler;
getMember.send(null);
}
function memberTimeoutHandler(){
getMember.abort(); //abort the timedout xmlhttprequest
setTimeout(function(){getOnlineMembers()}, 2000);
}
function memberReceivedHandler(){
if(getMember.readyState == 4 && getMember.status == 200){
var chat_members_div = document.getElementById('chat_members');
var xmldoc = getMember.responseXML;
var members_nodes = xmldoc.documentElement.getElementsByTagName("member");
var n_members = members_nodes.length;
for (i = 0; i < n_members; i++) {
chat_members_div.innerHTML += '<p>' + members_nodes[i].childNodes.nodeValue + '</p>';
chat_members_div.scrollTop = chat_members_div.scrollHeight;
}
mTimer = setTimeout('getOnlineMembers();',2000); //Refresh our chat members in 2 seconds
}
}
To prevent caching response you can try:
getMember.open("GET", "get_chat.php?get_member&t=" + Math.random(), true);
Check the responseXML is not empty by:
console.log(responseXML);
Also you might need to select the root node of the xml response before selecting childNodes:
var members_nodes = xmldoc.documentElement.getElementsByTagName("member"); //documentElement selects the root node of the xml document
hope this helps

Categories

Resources