AJAX: questions not rendering to the browser - javascript

I have been tasked with getting a small quiz application working. I saved my questions as a json file and conducting an http request. When I initialed ran a JSON.parse() of the questions, it rendered to the browser.
var output = document.getElementById('output');
// this allows us to keep it as a global value
var myObj = '';
loadQuestions();
console.log(myObj);
// var myQuestions = '[{"question":"What is your nearest star?","answers":{"a":"Alpha Centauri","b":"Barnard\'s Star","c":"Sirius","d":"Sol"},"correctAnswer":"d"},{"question":"What color is grass?","answers":{"a":"Blue","b":"Red","c":"Green","d":"Purple"},"correctAnswer":"c"}]';
// var myObj = JSON.parse(myQuestions);
// for (var i in myObj) {
// output.innerHTML += myObj[i].question + '? <br>';
// }
However, when I refactored it to do an AJAX call, it is iterating through the console, but not in the browser window:
var output = document.getElementById('output');
// this allows us to keep it as a global value
var myObj = '';
loadQuestions();
console.log(myObj);
function loadQuestions() {
// http request
// this will allow you to pull in
// the questions from the api that
// your questions or data is stored in
var a = new XMLHttpRequest();
a.open("GET", "https://api.myjson.com/bins/8xmud", true); // opened request with address with
a.onreadystatechange = function(){
if (a.readyState == 1) {
var myQuestions = JSON.parse(a.responseText);
console.log(myQuestions);
for (var i in myQuestions) {
output.innerHTML = myQuestions[i].question + '? <br>';
}
}
console.log(a);
}
a.send();
}
I thought it could be my for...in loop, but that's written correctly. I am unclear as to why, despite getting a Status: OK or 200, it is not iterating through the browser window as before.

var output = document.getElementById('output');
// this allows us to keep it as a global value
var myObj = '';
loadQuestions();
console.log(myObj);
function loadQuestions() {
// http request
// this will allow you to pull in
// the questions from the api that
// your questions or data is stored in
var a = new XMLHttpRequest();
a.open("GET", "https://api.myjson.com/bins/8xmud", true); // opened request with address with
a.onreadystatechange = function(){
if (a.readyState == 4) {
var myQuestions = JSON.parse(a.responseText);
console.log(myQuestions);
for (var i in myQuestions) {
output.innerHTML += myQuestions[i].question + '? <br>';
}
}
console.log(a);
}
a.send();
}
<div id ="output"></div>

Related

How to transfere data from one function to another using javascript

Hey everybody I have a problem.
I am building a website and I want to fetch data from two different xml files with two different functions.
ShowResult is used to get a game score and the name of a specific user.
GiveFeedback also needs the score from the first function to fetch a fitting feedback about this score from a different xml file.
I don´t get an error Message. My only problem is that the second function (giveFeedback) isn´t able to fetch data from the xml because it needs a variable (score) from the first function (showResults). Both functions work on their own but I am unable to “transfer” the score data from showResults to giveFeedback.
How can I transfer the score data to the function GiveFeedback or is there a better way to resolve this problem?
Thanks!
i tried some solutions (global variable, inserting the first function in the second,..) which were already posted but unfortunately i didn´t managed to get it running.
<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
showResult(xhttp.responseXML);
}
};
xhttp.open("GET", "user.xml", true);
xhttp.send();
function showResult(xml) {
var name = "";
var score = "";
path1 = "/userdb/user/name";
path2 = "/userdb/user/score";
var nodes = xml.evaluate(path1, xml, null, XPathResult.ANY_TYPE, null); var result = nodes.iterateNext();
name = result.childNodes[0].nodeValue;
var nodes = xml.evaluate(path2, xml, null, XPathResult.ANY_TYPE, null); var result = nodes.iterateNext();
//Thats wehere the variable (score) is, which i need for the second function (giveFeedback)
score = result.childNodes[0].nodeValue;
document.getElementById("user").innerHTML = "Congratulations " + name + ", you made " + score;
}
var xhttp2 = new XMLHttpRequest();
xhttp2.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
givefeedback(xhttp2.responseXML);
}
};
xhttp2.open("GET", "feedback.xml", true);
xhttp2.send();
function givefeedback(xml) {
var feedback = "";
// This is where it´s needed
if (score > 1){
path = "/feedback/congratulations[percentage=25]/text";
}
else if (score > 8){
path = "/feedback/congratulations[percentage=50]/text";
}
var nod = xml.evaluate(path, xml, null, XPathResult.ANY_TYPE, null);
var res = nod.iterateNext();
feedback = res.childNodes[0].nodeValue;
document.getElementById("feedback").innerHTML = feedback;
}
</script>
i managed to resolve my problem.
first of all i had to declare a global variable outside the functions.
Then i had to convert the fetched variable (score) to a Number.

How to live search/filter parsed JSON data with Javascript?

I'm trying to create a live search field to filter parsed JSON data with Javascript. The JSON data is rendering exactly how I want it to in HTML & CSS but the live filtering isn't working.
I'm new to this so it's probably something obvious, but I've tried & failed to find the answer online and I'm stuck. I'm having trouble calling the data to filter it - at least I think that's the issue.
The HTML:
<input type="text" placeholder="Search" id="filter_listings"/>
<section>
</section>
The Javascript:
var requestURL = 'atf.json';
var request = new XMLHttpRequest();
request.open('GET', requestURL);
request.responseType = 'text';
request.send();
request.onload = function() {
var directoryText = request.response;
var directory = JSON.parse(directoryText);
render_listings(directory);
}
var render_listings = function(jsonObj){
var listings = jsonObj['eateries'];
for(var i = 0; i < listings.length; i++) {
// where the html template is rendered & linked to JSON data
var myWrapper = document.createElement('div');
var myHeading = document.createElement('h1');
myHeading.textContent = listings[i].name;
section.appendChild(myWrapper).className = "wrapper";
myWrapper.appendChild(myHeading).className = "heading";
//etc
}
var filterListings = function(event){
keyword = input.value.toLowerCase();
var filtered_listings = listings.filter(function(user){
user = user.toLowerCase();
return user.indexOf(keyword) > -1;
});
render_listings(filtered_listings);
}
// filtering it
input = document.getElementById('filter_listings');
input.addEventListener('keyup', filterListings);
}
This line is where it breaks: user = user.toLowerCase(); Console says user.toLowerCase is a type error and not a function.
I'm just not sure how to link it to the JSON data. I've tried directory, jsonObj, eateries and listings. I've also tried moving the filter code to different spots, below the listings for loop, in the onload function but I get the same error.

Displaying products stored in MongoDB using AJAX and JavaScript

I have created a tracking and recommendation for customers, and it gets the data from the search engine. I'm using AJAX to get data of the products from MongoDB, and customers can also search for products that are stored in MongoDB. The problem is, I cannot display the products stored in MongoDB. There is no error in the console log, and when I search for products on the search engine, the recommendation works, but my products in MongoDB doesn't show up on my website.
HTML & AJAX
<input id="search_engine" type="text" name="search" placeholder="Search for accessories...">
<button id="search_item" onclick="loadContent()"></button>
<h2>Recommendations</h2>
<div id="RecomendationDiv"></div>
<script>
//Create recommender object - it loads its state from local storage
var recommender = new Recommender();
//Display recommendation
window.onload = showRecommendation;
//Searches for products in database
function loadContent() {
var search = document.getElementById("search_engine").value;
// Create request object
var request = new XMLHttpRequest();
// Create event handler that specifies what should happen when server responds
request.onload = function() {
// Check HTTP status code
if (request.status == 200) {
// Get data from server
var responseData = request.responseText;
// Add data to page
document.getElementById("product_grid").innerHTML = responseData;
} else
alert("Error communicating with server: " + request.status);
}
// Set up request with HTTP method and URL
request.open("POST", "php/search.php");
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// Send request
request.send("search=" + search);
//Add the search keyword to the recommender
recommender.addKeyword(search);
showRecommendation();
}
//Display the recommendation in the document
function showRecommendation() {
document.getElementById("RecomendationDiv").innerHTML =
recommender.getTopKeyword();
}
</script>
JavaScript
//Constructor for the recommender object
function Recommender() {
this.keywords = {}; //Holds the keywords
this.timeWindow = 10000; //Keywords older than this window will be deleted
this.load();
}
//Adds a keyword to the recommender
Recommender.prototype.addKeyword = function(word) {
//Increase count of keyword
if (this.keywords[word] === undefined)
this.keywords[word] = {
count: 1,
date: new Date().getTime()
};
else {
this.keywords[word].count++;
this.keywords[word].date = new Date().getTime();
}
console.log(JSON.stringify(this.keywords));
//Save state of recommender
this.save();
};
/* Returns the most popular keyword */
Recommender.prototype.getTopKeyword = function() {
//Clean up old keywords
this.deleteOldKeywords();
//Return word with highest count
var maxCount = 0;
var maxKeyword = "";
for (var word in this.keywords) {
if (this.keywords[word].count > maxCount) {
maxCount = this.keywords[word].count;
maxKeyword = word;
}
}
return maxKeyword;
};
/* Saves state of recommender. Currently this uses local storage,
but it could easily be changed to save on the server */
Recommender.prototype.save = function() {
localStorage.recommenderKeywords = JSON.stringify(this.keywords);
};
/* Loads state of recommender */
Recommender.prototype.load = function() {
if (localStorage.recommenderKeywords === undefined)
this.keywords = {};
else
this.keywords = JSON.parse(localStorage.recommenderKeywords);
//Clean up keywords by deleting old ones
this.deleteOldKeywords();
};
//Removes keywords that are older than the time window
Recommender.prototype.deleteOldKeywords = function() {
var currentTimeMillis = new Date().getTime();
for (var word in this.keywords) {
if (currentTimeMillis - this.keywords[word].date > this.timeWindow) {
delete this.keywords[word];
}
}
};
keith, have you tried testing it out with the rest of the code from the project first?

AJAX response text undefined

I am following below 2 posts:
Ajax responseText comes back as undefined
Can't return xmlhttp.responseText?
I have implemented the code in same fashion. But I am getting
undefined is not a function
wherever i am using callback() funtion in my code.
CODE:
function articleLinkClickAction(guid,callback){
var host = window.location.hostname;
var action = 'http://localhost:7070/assets/find';
var url = action + '?listOfGUID=' + guid.nodeValue;
console.log("URL "+url);
xmlhttp = getAjaxInstance();
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var response = JSON.parse(xmlhttp.responseText);
console.log(response);
console.log(xmlhttp.responseText);
callback(null, xmlhttp.responseText);// this is line causing error
}
else{
callback(xmlhttp.statusText);// this is line causing error
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send(null);
}
And I am calling it from this code:
var anchors = document.getElementsByTagName("a");
var result = '';
for(var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
var guid = anchor.attributes.getNamedItem('GUID');
if(guid)
{
articleLinkClickAction(guid,function(err, response) { // pass an anonymous function
if (err) {
return "";
} else {
var res = response;
html = new EJS({url:'http://' + host + ':1010/OtherDomain/article-popup.ejs'}).render({price:res.content[i].price});
document.body.innerHTML += html;
}
});
}
}
You are using a single global variable for your xmlhttp and trying to run multiple ajax calls at the same time. As such each successive ajax call will overwrite the previous ajax object.
I'd suggest adding var in front of the xmlhttp declaration to make it a local variable in your function so each ajax request can have its own separate state.
function articleLinkClickAction(guid,callback){
var host = window.location.hostname;
var action = 'http://localhost:7070/assets/find';
var url = action + '?listOfGUID=' + guid.nodeValue;
console.log("URL "+url);
// add var in front of xmlhttp here to make it a local variable
var xmlhttp = getAjaxInstance();
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var response = JSON.parse(xmlhttp.responseText);
console.log(response);
console.log(xmlhttp.responseText);
callback(null, xmlhttp.responseText);// this is line causing error
}
else{
callback(xmlhttp.statusText);// this is line causing error
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send(null);
}
In the future, you should consider using Javascript's strict mode because these "accidental" global variables are not allowed in strict mode and will report an error to make you explicitly declare all variables as local or global (whichever you intend).
I can't say if this is the only error stopping your code from working, but it is certainly a significant error that is in the way of proper operation.
Here's another significant issue. In your real code (seen in a private chat), you are using:
document.body.innerHTML += html
in the middle of the iteration of an HTMLCollection obtained like this:
var anchors = document.getElementsByTagName("a");
In this code, anchors will be a live HTMLCollection. That means it will change dynamically anytime an anchor element is added or removed from the document. But, each time you do document.body.innerHTML += html that recreates the entire body elements from scratch and thus completely changes the anchors HTMLCollection. Doing document.body.innerHTML += html in the first place is just a bad practice. Instead, you should append new elements to the existing DOM. I don't know exactly what's in that html, but you should probably just create a div, put the HTML in it and append the div like this:
var div = document.createElement("div");
div.innerHTML = html;
document.body.appendChild(div);
But, this isn't quite all yet because if this new HTML contains more <a> tags, then your live HTMLCollection in anchors will still change.
I'd suggestion changing this code block:
var anchors = document.getElementsByTagName("a");
var result = '';
for(var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
var guid = anchor.attributes.getNamedItem('GUID');
if(guid)
{
articleLinkClickAction(guid,function(err, response) { // pass an anonymous function
if (err) {
return "";
} else {
var res = response;
html = new EJS({url:'http://' + host + ':1010/OtherDomain/article-popup.ejs'}).render({price:res.content[i].price});
document.body.innerHTML += html;
}
});
}
}
to this:
(function() {
// get static copy of anchors that won't change as document is modified
var anchors = Array.prototype.slice.call(document.getElementsByTagName("a"));
var result = '';
for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
var guid = anchor.attributes.getNamedItem('GUID');
if (guid) {
articleLinkClickAction(guid, function (err, response) { // pass an anonymous function
if (err) {
//return "";
console.log('error : ' + err);
} else {
var res = response;
var html = new EJS({
url: 'http://' + host + ':1010/OtherDomain/article-popup.ejs'
}).render({
price: res.content[i].price
});
var div = document.createElement("div");
div.innerHTML = html;
document.body.appendChild(html);
}
});
}
}
})();
This makes the following changes:
Encloses the code in an IIFE (self executing function) so the variables declared in the code block are not global.
Changes from document.body.innerHTML += html to use document.body.appendChild() to avoid recreating all the DOM elements every time.
Declares var html so it's a local variable, not another accidental global.
Makes a copy of the result from document.getElementsByTagName("a") using Array.prototype.slice.call() so the array will not change as the document is modified, allowing us to accurately iterate it.

Javascript: XHR not handling multiple async requests

Hi I am trying to access one resource multiple times with with different parameters
In this case requesting
var domains = [
'host1',
'host2'
];
var requests = new Array();
for ( i in domains )
{
requests[i]=new request(domains[i]);
}
function request(site)
{
var url = 'get_remote_status.php?host='+site;
var queues = {};
http_request = new XMLHttpRequest();
http_request.open("GET", url, true, 'username', 'password');
http_request.onreadystatechange = function () {
var done = 4, ok = 200;
if (http_request.readyState == done && http_request.status == ok) {
queues = JSON.parse(http_request.responseText);
var queuesDiv = document.getElementById('queues');
print_queues(queues, queuesDiv, site);
}
};
http_request.send(null);
}
However, only one of of the requests is being handled by the code lambda. Chromium reports that both requests have been received and is viewable in the resourced pane.
Also if I make the request synchronous then it works fine. However this is not acceptable to the release code as a request may timeout.
Thanks
Define http_request using var. Currently, you're assigning the XHR object to a global variable. Because of this, your script can only handle one XHR at a time.
Relevant erroneous code:
function request(site)
{
var url = 'get_remote_status.php?host='+site;
var queues = {};
http_request = new XMLHttpRequest();
Proposed change:
function request(site)
{
var url = 'get_remote_status.php?host='+site;
var queues = {};
var http_request = new XMLHttpRequest(); //VAR VAR VAR !!!
When you omit var before a variable, the variable will be defined in the global (window) scope. If you use var before a variable, the variable is defined within the local scope (in function request, in this case).
In fact it is possible to run multiple async xhr call but you have to give them an unique id as parameter to be able to store and load them locally in your DOM.
For example, you'd like to loop on an array and make a ajax call for each object. It's a little bit tricky but this code works for me.
var xhrarray={};
for (var j=0; j<itemsvals.length; j++){
var labelval=itemsvals[j];
// call ajax list if present.
if(typeof labelval.mkdajaxlink != 'undefined'){
var divlabelvalue = '<div id="' + labelval.mkdid + '_' + item.mkdcck + '" class="mkditemvalue col-xs-12 ' + labelval.mkdclass + '"><div class="mkdlabel">' + labelval.mkdlabel + ' :</div><div id="'+ j +'_link_'+ labelval.mkdid +'" class="mkdvalue">'+labelval.mkdvalue+'</div></div>';
mkdwrapper.find('#' + item.mkdcck + ' .mkdinstadivbody').append(divlabelvalue);
xhrarray['xhr_'+item.mkdcck] = new XMLHttpRequest();
xhrarray['xhr_'+item.mkdcck].uniqueid=''+ j +'_link_'+ labelval.mkdid +'';
console.log(xhrarray['xhr_'+item.mkdcck].uniqueid);
xhrarray['xhr_'+item.mkdcck].open('POST', labelval.mkdajaxlink);
xhrarray['xhr_'+item.mkdcck].send();
console.log('data sent');
xhrarray['xhr_'+item.mkdcck].onreadystatechange=function() {
if (this.readyState == 4) {
console.log(''+this.uniqueid);
document.getElementById(''+this.uniqueid).innerHTML = this.responseText;
}
};
}
}
You have to set each xhr object in a global variable object and define a value xhrarray['xhr_'+item.mkdcck].uniqueid
to get its unique id and load its result where you want.
Hope that will help you in the future.

Categories