I am working on a small project for University using JavaScript, JSON and AJAX to pull information from 3 seperate restaurant menus (stored in JSON files) and displaying them in a list once the relevant button has been clicked.
This worked using one menu, having a button with an event listener that ran the loadAjax function and displayed the relevant menu information.
I've tried to expand this using 3 buttons, with an event listener on each that passes the name of the JSON file through the function parameter. This no longer works, and only the last JSON file is displayed, on window load, without clicking a button.
I'm pretty stuck at this stage and want to avoid having three separate functions (for obvious reasons). The code is below, any help would be much appreciated! I may have made a minor error so apologies if this is a silly question.
var weekdayBtn = document.getElementById("weekdayBtn"),
saturdayBtn = document.getElementById("saturdayBtn"),
sundayBtn = document.getElementById("sundayBtn");
weekdayBtn.addEventListener("click", loadAjax("weekday.json"), false);
saturdayBtn.addEventListener("click", loadAjax("saturday.json"), false);
sundayBtn.addEventListener("click", loadAjax("sunday.json"), false);
function loadAjax(menuData) {
var request = new XMLHttpRequest();
request.open('GET', menuData);
request.onreadystatechange = function() {
if ((request.readyState === 4) && (request.status === 200)) {
var menu = JSON.parse(request.responseText);
var output = "";
for (var key in menu) {
output += "<li>" + menu[key]["Title"] + ", " + menu[key]["Description"] + ". " + menu[key]["Price"] + " </li>";
}
var menu = document.getElementById('menu');
menu.innerHTML = output;
}
}
request.send();
}
The addEventListener methods requires a function as second argument so your loadAjax method must return a function:
function loadAjax(menuData) {
return function () {
var request = new XMLHttpRequest();
request.open('GET', menuData);
request.onreadystatechange = function() {
if ((request.readyState === 4) && (request.status === 200)) {
var menu = JSON.parse(request.responseText);
var output = "";
for (var key in menu) {
output += "<li>" + menu[key]["Title"] + ", " + menu[key]["Description"] + ". " + menu[key]["Price"] + " </li>";
}
var menu = document.getElementById('menu');
menu.innerHTML = output;
}
}
request.send();
}
}
in this way the inner function will be used as event listener with the menuData variable in its scope.
Related
I have an html table of names and I want to be able to click on a name and retrieve additional details of the person and display them in an 'Alert' popup. I plan to use the XMLHttpRequest to send the name to a php file to process it. I can retrieve the name from the table with no trouble but I have run some diagnostic tests and cannot seem to trigger the XMLHttpRequest using the onreadystatechange method.
This is my code that retrieves the name:-
function getDetails(x){
var tr1 = x.parentNode.rowIndex;
var td1 = x.cellIndex;
var table = document.getElementById("selectedTeams");
//Diagnostic
//document.getElementById("tr1").innerHTML = "1st Row index is: " + tr1;
//document.getElementById("td1").innerHTML = "1st Column index is: " + td1;
player = table.rows[tr1].cells[td1].innerHTML;
player = player.replace("<b>", "");
player = player.replace("</b>", "")
player = player.trim();
//Diagnostic
//document.getElementById("res3").innerHTML = "The player selected is: " + player;
getName(player);
//Diagnostic
//alert("This will be the "+ player + " details");
}
This gets the player's name. It works well. The player's name is then passed to the getName() function. From my diagnostics it does not trigger the onreadystatechange and go through the subsequent function. Am I using the right method here or is there a more appropriate one and is the rest of the code ok. The code for the getName() function is :-
function getName(str){
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200){
//document.getElementById("res3").innerHTML = this.responseText;
alert(this.responseText);
}
xmlhttp.open("GET", "playerDetails.php?q= " + str, true);
xmlhttp.send();
//Diagnostic
//alert("after onreadystatechange");
}
//Diagnostic
//alert("after function");
}
You've put the open and send calls inside of the onreadystatechange event handler, which will never be run until open and send are called. See the catch-22?
Fix this issue by moving the calls to open and send from the onreadystatechange event handler into the enclosing getName function body like this:
function getName(str) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200){
//document.getElementById("res3").innerHTML = this.responseText;
alert(this.responseText);
}
//Diagnostic
//alert("after onreadystatechange");
};
xmlhttp.open("GET", "playerDetails.php?q= " + str, true);
xmlhttp.send();
//Diagnostic
//alert("after function");
}
i'm trying to make auto complete with pure javascript.
Scenario is when type to input some letters it will search movies from omdbapi.
I make it like that:
i have input which users can search movies, i have get data from input value:
<input type="text" class="form-control" id="searchMovie" value="">
and here i get movies and make html markup with javascript for show these results in html:
var searchInput = document.getElementById("searchMovie");
// get movie
searchInput.onkeydown = function() {
var searchData = document.getElementById("searchMovie").value;
if (searchData.length >= 3 ) {
var request = new XMLHttpRequest();
request.open('GET', 'http://www.omdbapi.com/?s=' + searchData + '&apikey=000000', true);
request.onload = function () {
// Begin accessing JSON data here
var data = JSON.parse(this.response);
const wrapper = document.createElement('div');
app.appendChild(wrapper);
var results = data;
if (request.status >= 200 && request.status < 400) {
console.log(data);
Object.keys(data.Search).map(function(key, index) {
console.log(data.Search[index].Title);
const searchResultsContainer = document.createElement('div');
searchResultsContainer.setAttribute('class', 'row');
const h1 = document.createElement('h1');
h1.textContent = data.Search[index].Title;
wrapper.appendChild(searchResultsContainer);
searchResultsContainer.appendChild(h1);
console.log(searchResultsContainer);
});
} else {
console.log('error');
}
};
request.send();
}
};
everything work well but problem is:
when i try to delete keyword which i wrote and write new one results not disappear from html, i want change
You need to capture the change in the text input. Adding your code to a function and binding the input to oninput function. When there is a change in the value of the input it will rerun the api call. Furthermore, you need to clear out the old result.
<input type="text" class="form-control" id="searchMovie" value="" oninput"apiCall()">
<script>
function apiCall(){
var searchInput = document.getElementById("searchMovie");
// get movie
searchInput.onkeydown = function() {
var searchData = document.getElementById("searchMovie").value;
if (searchData.length >= 3 ) {
while (document.getElementsByClassName('autoComplete')[0]) {
document.getElementsByClassName('autoComplete')[0].remove();
}
var request = new XMLHttpRequest();
request.open('GET', 'http://www.omdbapi.com/?s=' + searchData + '&apikey=000000', true);
request.onload = function () {
// Begin accessing JSON data here
var data = JSON.parse(this.response);
var wrapper = document.createElement('div');
wrapper.className = "autoComplete";
app.appendChild(wrapper);
var results = data;
if (request.status >= 200 && request.status < 400) {
console.log(data);
Object.keys(data.Search).map(function(key, index) {
console.log(data.Search[index].Title);
const searchResultsContainer = document.createElement('div');
searchResultsContainer.setAttribute('class', 'row');
const h1 = document.createElement('h1');
h1.textContent = data.Search[index].Title;
wrapper.appendChild(searchResultsContainer);
searchResultsContainer.appendChild(h1);
console.log(searchResultsContainer);
});
} else {
console.log('error');
}
};
request.send();
}
}
</script>
That should remove the wrapper element you added and its children and populate a new one with new data. I can't really test this to make sure it works as I can not see the rest of your code. But it should work. if not I can help you to figure out any errors.
Also, I would consider making wrapper just a hidden div that you can easily clear and unhide when needed. It would be much easier and you wouldn't need to add and remove so many elements. just wrapper.innerHTML = ""; then wrapper.innerHTML = newRowSet; and done
Instead of setting h1.textContent = data.Search[index].Title; update this to h1.innerHTML = data.Search[key].Title;
I got this mvc core application. One of its methods looks like this(for now)
public IActionResult Call(string call)
{
Response.ContentType = "text/plain";
return Ok (call);
}
and a javascript in browser looks like that
var xhttp = new XMLHttpRequest();
xhttp.withCredentials = true;
xhttp.open("GET", request, true);
xhttp.onreadystatechange = function ()
{
if (this.readyState == 4)
{
if (this.status == 200)
{
SetAnswerText(this.responseText);
}
else
{
SetApiCallTextAreaValue("request - \n" + request + "\n failed; status = " + this.status);
}
}
else
{
SetApiCallTextAreaValue("current status is " + this.readyState + "\n" + this.responseText);
}
}
for some reason, I get only notification with readystate==3(LOADING), and never.. with readystate==4(DONE) which im expecting.
Can you help me figuring it out why thats happaning?
btw, if I open an url to this Call method in browser like https://..../Call/?call=123 it works absoulutely fine..
omg.. forgot to change function name from SetAnswerText to SetApiCallTextAreaValue..
have to sleep more..
found a error only when I looked at code in browser :P
i have some problrm creating the radio buttons dynamically. in my problem i am requesting data from server in json formate than i check if it contains options i have to create the radio buttons otherwise simply creates the txt area of field to submit the answer. than again i parse it in json formate and send to the server and if my question is write i get new url for next question and so on...
my question is how can i create the radio buttons and read the data from it and than parse that data like {"answer": "something"}.my code is bellow:
enter code herefunction loadDoc(url) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
var data = JSON.parse(this.responseText);
document.getElementById("my_test").innerHTML = data.question;
// Send the answer to next URL
if(data.alternatives !== null){
createRadioElement(div,);
}
var answerJSON = JSON.stringify({"answer":"2"});
sendAnswer(data.nextURL, answerJSON)
}
};
xhttp.open("GET", url, true);
xhttp.send();
}
function sendAnswer(url, data) {
xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/json");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var data = JSON.parse(this.responseText);
console.log(this.responseText);
loadDoc(data.nextURL);
}
}
// var data = JSON.stringify({"email":"hey#mail.com","password":"101010"});
xhr.send(data);
}
function createRadioElement(name, checked) {
var radioHtml = '<input type = "radio" name="' + name + '"';
if ( checked ) {
radioHtml += ' checked="checked"';
}
radioHtml += '/>';
var radioFragment = document.createElement('div');
radioFragment.innerHTML = radioHtml;
return radioFragment.firstChild;
}
I'm only guessing since you have some things in your posted code that won't even run, but createRadioElement returns a detached node which you never actually inject into your document.
E.g.,
document.body.appendChild(createRadioElement());
I am attempting to append DB records retrieved into buttons which I can click on to go to the next page.
function mywall(){
$("#wallcontentset").empty();
var xmlhttp = new XMLHttpRequest();
var url = serverURL() + "/category.php";
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
mywallresult(xmlhttp.responseText);
};
}
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
function mywallresult(response) {
var arr = JSON.parse(response);
var i;
$("#wallcontentset").empty();
for(i = 0; i < arr.length; i++) {
var a = document.createElement("a");
a.setAttribute("href", "#");
a.setAttribute("onclick","listitembycategory.html?categoryid=" + arr[i].categoryid);
a.setAttribute("class","ui-btn");
a.innerHTML = arr[i].categoryname.toString();
$("#wallcontentset").append(a);
}
}
The above are the set of functions that I had coded and placed in the script. The function mywall() is working fine, it retrieves every record in my database.
However I had some issues with the function mywallresult().
It creates a button for every record retrieved, however the button does not link to the next page when clicked. I couldn't identify what's wrong with my a.setAttribute.
Anyone could help me out please?
You have to merely replace this:
a.setAttribute("href", "#");
a.setAttribute("onclick","listitembycategory.html?categoryid=" + arr[i].categoryid);
by this:
a.setAttribute("href", "listitembycategory.html?categoryid=" + arr[i].categoryid);