How to subset specific object properly in JS - javascript

I'm currently doing some practice and i want to print the titles of each movie on this api:
https://jsonmock.hackerrank.com/api/movies?Year=1998
Basically, I want each title to be printed for the first page (or preferably a specific page).
This is the code I have:
<script>
function printTItles(year) {
var res;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
res = JSON.parse(this.responseText);
for(var i=0;i<res.per_page;i++){
document.getElementById("demo").innerHTML = res.data.i.Title;
}
};
}
xmlhttp.open("GET", "https://jsonmock.hackerrank.com/api/movies?Year=<year>", true);
xmlhttp.send();
}
</script>
I know the problem is in res.data.i.title but I'm not sure how to fix it.

You are trying to access the element at the index i in your loop, like you would access a property of an object. To get the element at position i in your res.data array, you need the square bracket access [ ]
Also, you are not replacing the year parameters in your request for the year parameters passed to your function. You might want to check that out.
Here I have use the year 2018 as an example.
function printTItles(year) {
var res;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
res = JSON.parse(this.responseText);
for(var i=0;i<res.per_page;i++){
document.getElementById("demo").innerHTML = res.data[i].Title;
}
};
}
xmlhttp.open("GET", "https://jsonmock.hackerrank.com/api/movies?Year=2018", true);
xmlhttp.send();
}
printTItles();
<div id="demo"></div>
You could add some more improvement. For example, at each iteration, you are replacing the content of your #demo element. This cause only the last title to be shown. You could, instead, append the data to the already existing html of the div. Or, like I did in this case, build your string before setting it as the new innerHTML value.
function printTItles(year) {
var res;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
res = JSON.parse(this.responseText);
var output = "";
for(var i=0;i<res.per_page;i++){
if(res.data[i]) {
output += res.data[i].Title + '<br />';
}
}
document.getElementById("demo").innerHTML = output;
};
}
xmlhttp.open("GET", "https://jsonmock.hackerrank.com/api/movies?Year=2018", true);
xmlhttp.send();
}
printTItles();
<div id="demo"></div>
I've also added a condition to check if there is an element at res.data[i].

Related

JS: problem with for loop (only one image is shown)

I am completely new to javascript and web development.
I'm having a problem with the for loop; what happens to me is that the ids come back to me all together and not individually in order to retrieve the relative image and title through the id, so I can't recover images and title from the json array.
Specifically I get the error:
Uncaught TypeError: Cannot read properties of undefined (reading 'immagine') at XMLHttpRequest.xmlhttp.onreadystatechange
Warning: I have no problems in how to retrieve items in a json array because I know how to do it very well
This is my code:
//here I get all the articles, so my json array
var xmlhttp = new XMLHttpRequest();
var url = "https://wjko5u1234.execute-api.us-east-2.amazonaws.com/articles";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var allart = JSON.parse(this.responseText);
var container=document.getElementById("slideshow")
for(var i = 0; i < allart.Items.length; i++)
{
container.innerHTML += '<div class="slideshow-container"></div>';
document.getElementById("id").innerHTML += "<br/>" + allart.Items[i].id;
myFunction1(allart.Items[i].id);
}
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
//here I pass the id via function call, and for each id I want to retrieve image and title which has that specific id only i get the set of ids without having one at a time to retrieve what i need
function myFunction1(id) {
var xmlhttp = new XMLHttpRequest();
var url = "https://wjko5u1234.execute-api.us-east-2.amazonaws.com/articles/"+id;
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
document.getElementById("img1").src="articoli_img/"+myArr.Item.immagine;
document.getElementById("title1").innerHTML = myArr.Item.titolo;
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
I would be very thankful for any help.
It seems that "Item" prop doesn't exist in returned object (located in myFunction1()) (did you mean to write myArr.immagine?)
Since you are new: I recommend to use for-each loops in collections, by using:
for(let item of allart.Items) {
.....
}

I can't use a Object, which was previously loaded via AJAX Request, in a function call

I'm trying to write a chrome extension, that closes a tab when it's loaded and contains specific keywords, which I'm storing in banned.json. But following code gives me an error:
//background.js:
var obj;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if(xhttp.readyState == 4 && xhttp.status == 200){
obj = JSON.parse(xhttp.response);
console.log(obj.banned);
}};
xhttp.open('GET', "banned.json", true);
xhttp.send();
chrome.webNavigation.onCompleted.addListener(closeTab, obj.banned); // error is here
function closeTab(e) {
if (!e.frameId) {
console.log("Hallo2");
chrome.tabs.remove(e.tabId);
}
}
It says that it cannot read property banned of undefined. How can that be? obj is defined in the first line and I can reference it in the if-block. Can anyone help me?
EDIT:
banned.json:
{
"banned": [
"https://www.google.de/",
"youtube.com"
]
}
You need put "chrome.webNavigation.onCompleted.addListener" sentence in "xhttp.onreadystatechange" function.
var obj;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if(xhttp.readyState == 4 && xhttp.status == 200){
obj = JSON.parse(xhttp.response);
console.log(obj.banned);
chrome.webNavigation.onCompleted.addListener(closeTab, obj.banned);
}};
xhttp.open('GET', "banned.json", true);
xhttp.send();
function closeTab(e) {
if (!e.frameId) {
console.log("Hallo2");
chrome.tabs.remove(e.tabId);
}
}
EDIT
You can try changing banned.json as follows.
{
"banned":
"url" : [
{"hostContains":"https://www.google.de/"},
{"hostContains":"youtube.com"}
]
}
Solution:
change banned.json to:
[
"www.google.de",
"www.youtube.com/?gl=DE"
]
"chrome.webNavigation.onCompleted.addListener" sentence mustn't be in "xhttp.onreadystatechange" function else you're gonna get an error.

'undefined' error even after JSON.parse

<!DOCTYPE html>
<html>
<head>
<title>Imagery Gallery</title>
</head>
<body>
<h2>Location List</h2>
<!-- image gallery will be displayed in the results <div> -->
<div id="results"></div>
<!-- JavaScript codes -->
<script src="HTTPRequest.js"></script>
<script>
//Send request to the server to get the JSON dataset showing the list of locations
//The URL to request is "http://geopingyin.com/gis/Locations.php"
//The request function sendHttpRequest(sURL) is defined in the HTTPRequest.js file
sendHttpRequest("http://geopingyin.com/gis/Locations.php");
//When the JSON dataset (JSONData, a text string) is successfully returned to the browser,
//The function handleResponseData(JSONData) will be automatically called.
//Complete the following function to process the JSON dataset.
function handleResponseData(JSONData) {
var obj = JSON.parse(JSONData);
for (i in obj) {
i += obj[i] + "<br>";
document.getElementById("results").innerHTML = i.Locations;
}
}
//place your codes here for the imagery gallery
</script>
</body>
</html>
This code is giving me an 'undefined' answer whenever I run it. After lots of research it seems like most people have issues with 'undefined' because they are using strings and not objects. However in my code I used a JSON.parse in order to create an object off of the original string, and it still comes up as undefined. I wish to use JSON.parse in order to change my array into objects and then loop through and display each one, yet I can not seem to figure out how to go about this. Any help would be greatly appreciated!
Also here is my HTTPRequest.js code just in case
var xmlHttp = createHttpRequestObj(); //Http request object
//Create HTTP request object
function createHttpRequestObj() {
var xmlHttpObj;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
try {
xmlHttpObj = new XMLHttpRequest();
} catch (e) {
xmlHttpObj = false;
}
} else {
// code for IE6, IE5
try {
xmlHttpObj = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
xmlHttpObj = false;
}
}
if (!xmlHttpObj)
alert("Cannot create the Http request object");
else {
return xmlHttpObj;
}
}
//Send HTTP request with the URL
//Function handleServerResponse() will be used to interpret the response
function sendHttpRequest(sURL) {
if (xmlHttp.readyState == 0 || xmlHttp.readyState == 4) {
xmlHttp.open("GET", sURL, true);
xmlHttp.onreadystatechange = handleServerResponse;
xmlHttp.send();
} else {
setTimeout(function() {
sendHttpRequest(sURL);
}, 1000);
}
}
//Handel HTTP response
function handleServerResponse() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
xmlResponse = xmlHttp.responseText;
//Handle the xmlResponse
handleResponseData(xmlResponse);
}
}
}
THANK YOU!
undefined results when you try to access data that doesn't exist. This can result from trying to read an object key from what is actually a string; but can equally happen when reading a nonexistent key from a real object (which is one part of what was going wrong in your code.)
The issues are within your handleResponseData function; I've commented it below to describe what's going wrong:
function handleResponseData(JSONData) {
var obj = JSON.parse(JSONData); // so far so good
/* obj only contains one key, "Locations", so `obj` isn't
what you want to be iterating over; instead you want to iterate
within obj.Locations: */
for (i in obj) {
/* Two problems in this next line: first, it's trying to
concatenate objects onto a string (which will result in
the string "[object Object]"); second, it's trying to
concatenating them onto the iterator, which would
interfere with the loop: */
i += obj[i] + "<br>";
/* This line should not be inside the loop, and it shouldn't be
trying to read the Locations key from child objects, because
that key was on the parent: */
document.getElementById("results").innerHTML = i.Locations;
}
}
Below is a corrected version (I've assumed the .Name key from each object within the Locations array is what you want):
var xmlHttp = createHttpRequestObj();
function createHttpRequestObj() {
// Code for handling obsolete browsers omitted for brevity
return new XMLHttpRequest();
}
function sendHttpRequest(sURL) {
if (xmlHttp.readyState == 0 || xmlHttp.readyState == 4) {
xmlHttp.open("GET", sURL, true);
xmlHttp.onreadystatechange = handleServerResponse;
xmlHttp.send();
} else {
setTimeout(function() {
sendHttpRequest(sURL);
}, 1000);
}
}
function handleServerResponse() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
xmlResponse = xmlHttp.responseText;
handleResponseData(xmlResponse);
}
}
}
sendHttpRequest("https://geopingyin.com/gis/Locations.php");
function handleResponseData(JSONData) {
var obj = JSON.parse(JSONData);
var output = "";
for (i in obj.Locations) {
output += obj.Locations[i].Name + "<br>";
}
document.getElementById("results").innerHTML = output
}
<h2>Location List</h2>
<div id="results"></div>

GET function console error

The logic:
my_function looks through file.txt, if it finds the word "Hello", returns true. If not, false.
The problem:
Uncaught type error: contents.includes is not a function
Limitations:
Can only use plain javascript
function my_function() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(contents) {
if (this.readyState == 4 && this.status == 200) {
//contents variable now contains the contents of the textfile as string
//check if text file contains the word Hello
var hasString = contents.includes("Hello");
//outputs true if contained, else false
console.log(hasString);
}
};
xhttp.open("GET", "http://www.example.com/file.txt", true);
xhttp.send();
}
use this.responseText instead of that parameter contents
this.responseText is the response of your ajax
function my_function() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//contents variable now contains the contents of the textfile as string
//check if text file contains the word Hello
var hasString = this.responseText.includes("Hello");
//outputs true if contained, else false
console.log(hasString);
}
};
xhttp.open("GET", "http://www.example.com/file.txt", true);
xhttp.send();
}

How to make update function check if it has loaded same context as there already is?

So I have next update function:
function update() {
var xmlhttp;
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
var success = false;
var objects = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];
for (var i = 0; i < objects.length && !success; i++) {
try {
xmlhttp = new ActiveXObject(objects[i]);
success = true;
} catch (e) { };
}
if (!success) throw new Error("AJAX is unavailabe");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
document.getElementById('usersList').innerHTML = xmlhttp.responseText;
};
}
xmlhttp.open("get", "buttons.html", true);
xmlhttp.send(null);
}
update();
setInterval(update, 5000);
so what I want it not to update documents contents if it has loaded same stuff that there is already. How to do such thing?
Something like:
if (xmlhttp.readyState == 4 &&
document.getElementById('usersList').innerHTML != xmlhttp.responseText) {
document.getElementById('usersList').innerHTML = xmlhttp.responseText;
};
EDIT: After patrick's comment in the page, it looks better to store the response somewhere and compare it to the new instead of relying on the innerHTML that can change the original HTML string.
You'll need to do the download first to determine what text you're comparing in the first place. I'm assuming buttons.html is somehow dynamic, so when you download it, you need to compare it to what's already in the innerHTML of userList.
...
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4) {
if(document.getElementById('usersList').innerHTML != xmlhttp.responseText)
document.getElementById('usersList').innerHTML = xmlhttp.responseText;
};
}
...
In addition, if you're going to do a lot of ajax, I suggest using a library such as jQuery. Ajax calls are as simple as
$('#userList').load('buttons.html');
or
$.ajax({
url: 'buttons.html',
success: function(data) {
if ($('#userList').html() != data)
$('#userList').html(data);
}
});

Categories

Resources