I am new in XML. Here I don't understand that why we pass "this" to myfunction(). I am waiting for your informative answers. Looking forward.
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xmlhttp.open("GET", "cd_catalog.xml", true);
xmlhttp.send();
}
function myFunction(xml) {
var x, i, xmlDoc, txt;
xmlDoc = xml.responseXML;
txt = "";
x = xmlDoc.getElementsByTagName("ARTIST");
for (i = 0; i< x.length; i++) {
txt += x[i].childNodes[0].nodeValue + "<br>";
}
document.getElementById("demo").innerHTML = txt;
}
The this keyword refers to the current context.
this is then passed into myFunction() as an argument.
myFunction() then takes the Object (now called xml) and does stuff with it.
To get technical, take a look at the MDN page describing XMLHHttpRequest()
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
All the list of properties are in the current context. You will notice one of them being responseXML. This is the attribute you are referring to in your code:
xmlDoc = xml.responseXML
Hope this helps.
Related
I'm having a problem; I have the following program code:
var xmlhttp = new XMLHttpRequest();
var url = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle";
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var allmot = JSON.parse(this.responseText);
console.log(allmot);
for(var i = 0, len = allmot.Items.length; i < len; i++)
{
id=allmot.Items[i].id
var url1 = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle/"+id;
console.log(url1);
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
document.getElementById("img").src = myArr.Item.image;
document.getElementById("brd").innerHTML = myArr.Item.brand;
}
};
xmlhttp.open("GET", url1, true);
xmlhttp.send();
}
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
allmot is as follows:
Items: Array (4)
0: {brand: 'Guzzi', id: '123456', image: 'moto_guzzi.jpg', date: '27/11/2021 '}
1: {brand: 'Bimota', id: '135623', image: 'bimota.jpg', date: '04/12/2021 '}
2: {brand: 'Ducati', id: '123789', image: 'b_desertx.jpg', date: ' 04/12/2021 '}
3: {brand: 'Benelli', id:' 146975 ', image:' benelli.jpg ', date: '27/11/2021'}
url1 returns (according to the for loop):
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/123456
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/135623
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/123789
https://wjko5k6250.execute-api.us-east-2.amazonaws.com/articles/146975
and so far everything seems to be fine.
The problem is in myArr; I noticed that it returns the image and brand of the last element only, so the one that has id equal to 146975.
Therefore there seems to be problems with the for loop.
Can anyone kindly help me? Thank you all.
As first correction I'd not recycle the XHR object from the outer loop in the inner loop.
When you say xmlhttp.onreadystatechange = function() ... in the inner loop, the xmlhttp is already in the readystate, obtained in the outer loop.
So, without further checking what is going on, I'd use two XHR objects (maybe like outerXmlhttp and innerXmlhttp). I'd also recreate the inner XHR for every cycle with:
var innerXmlhttp;
at the top of the outer closure.
Then, inside the cycle do:
innerXmlhttp = new XMLHttpRequest();
This is because of variable hoisting. If you just do this:
var innerXmlhttp = new XMLHttpRequest();
inside the cycle you may get a different behaviour. Just don't do it and write what you mean (hoist variables and assign them where you actually need it).
If all of this isn't enough ask a new, more precise question about what is going on.
This is your code with the corrections:
var outerXmlhttp = new XMLHttpRequest();
var url = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle";
outerXmlhttp.onreadystatechange = function() {
var innerXmlhttp;
if (this.readyState == 4 && this.status == 200) {
var allmot = JSON.parse(this.responseText);
console.log(allmot);
for(var i = 0, len = allmot.Items.length; i < len; i++)
{
id=allmot.Items[i].id
var url1 = "https://wjko5k6250.execute-api.us-east-2.amazonaws.com/motorcycle/"+id;
console.log(url1);
innerXmlhttp = new XMLHttpRequest();
innerXmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myArr = JSON.parse(this.responseText);
console.log(myArr);
document.getElementById("img").src = myArr.Item.image;
document.getElementById("brd").innerHTML = myArr.Item.brand;
}
};
innerXmlhttp.open("GET", url1, true);
innerXmlhttp.send();
}
}
};
outerXmlhttp.open("GET", url, true);
outerXmlhttp.send();
EDIT: #Teemu's eagle eye
As #Teemu points out in his comment, if you reassign values over and over to the same DOM objects like this:
document.getElementById("img").src = myArr.Item.image;
document.getElementById("brd").innerHTML = myArr.Item.brand;
you're clearly overwriting whatever value was there before. Instead, you should create and append those DOM objects, more like this:
var img = document.createElement("img");
img.src = myArr.Item.image;
var brd = document.createElement("p");
brd.innerText = myArr.Item.brand;
document.getElementById("motlist").append(img);
document.getElementById("motlist").append(brd);
Obviously, you'll need a <div id="motlist"></div> element or some other parent in the DOM to which to append the new elements.
For paging you may also want to clear those elements in the list... but here we're going overboard.
I have been going crazy about this for a couple hours. Can someone help me? I am getting "xmlDoc is not a function" error.
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
loadXMLDoc();
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xmlhttp.open("GET", "https://www.w3schools.com/xml/cd_catalog.xml", true);
xmlhttp.send();
}
function myFunction(xml) {
var item = "Bonnie Tyler";
var xmlDoc = xml.responseXML;
var x = xmlDoc('ARTIST').find(includes(item));
console.log(x);
}
try this
function myFunction(xml) {
var item = "Bonnie Tyler";
var xmlDoc = xml.responseXML;
var x = [...xmlDoc.querySelectorAll('ARTIST')].find(el=>el.textContent == item);
console.log(x);
}
your xmlDoc is xml document, not a function, you can only apply some methods on.
I have tried nearly everything works for NodeJS but found a solution by using xml2js package. Works perfectly!
I've a piece of JavaScript that gets called when a button is clicked.
The function manipulates some DOM (makes the page opaque, reveals an animation) and then loops through AJAX calls to 'script.php' many times. When that's over it reloads the page, fresh.
My issues is that on Chrome and IE, for the life of me, I can't get the DOM modifications to happen before the AJAX runs and completes. It works fine on Firefox.
I've tried calling sequentially in the code. Nesting each part in a function and in a third, calling each in order.
I've tried to use a promise. Everytime, the AJAX runs and completes, the screen flickers with the DOM mods just before the page reloads.
How is this usually managed?
The problem in a nutshell.
What are some ways I can force Chrome (and Edge) to update the DOM first and then run the AJAX rather than the other way around.
My code is here:
function Backup(OrgRowIDs) {
document.getElementById('Overlay').style.visibility="visible";
document.getElementById('Overlay').style.display="block";
document.getElementById('ActionWindow').style.visibility="visible";
document.getElementById('ActionWindow').style.display="inline";
function GenerateBackupID () {
var Characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
var ID = '';
for (var i = 1; i <= 12; i++) {
var pos = Math.floor((Math.random() * 60) + 1)
ID = ID + Characters.substring(pos, pos + 1);
}
return ID;
}
function RecordBackupSessionID() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
return;
}
}
xhttp.open("GET", "../AJAX/RecordBackupID?backupfile=" + OrgRowIDs[i] + "&backupid=" + BID , false);
xhttp.send();
}
for (i = 0; i < OrgRowIDs.length; i++){
BID = GenerateBackupID();
RecordBackupSessionID();
function BackupFiles(i) {
for (j = 0; j < 20; j++) {
function BackupEndPoints(j) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//do something if we want.
}
}
xhttp.open("GET", "../AJAX/BackupFiles?backupfile=" + OrgRowIDs[i] + "&endpoint=" + j + "&backupid=" + BID , false);
xhttp.send();
}
BackupEndPoints(j)
}
}
BackupFiles(i)
}
location.reload();
}
My problem seems to lie somewhere in between the subfunction calling of LoadXML. It seems that the xml data becomes null for some weird reason, and I have no idea how to fix that. Stackexchange seemed to have loads of similar questions but many were unanswered or the answer they had did not help my case.
function load() {
var xmlhttp;
xmlhttp = new XMLHttpRequest();
var idname = document.getElementById("name").value;
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log(this); //it obtains it here...
LoadXML(this, idname);
}
};
xmlhttp.open("GET", "helper_database.xml", false);
xmlhttp.overrideMimeType('text/xml');
xmlhttp.send();
}
function LoadXML(xml, name) {
var x, i, xmlDoc, nametxt, areEqual;
xmlDoc = xml.responseXML;
nametxt = name;
console.log("HERE \n" + xmlDoc); //...but it becomes null.
x = xmlDoc.getElementsByTagName("name"); //this returns the error of "Cannot read property 'getElementsByTagName' of null"
console.log("muuttujan x eka: " + x[0]);
for (i = 0; i < x.length; i++) {
if (areEqual = xmlDoc.getElementsByTagName("name").toUpperCase() === nametxt.toUpperCase()) {
document.getElementById("ComFocus").value = x[i];
}
}
}
Here is the helper_database.xml
<Character>
<name>test</name>
<stats>
<Com>1</Com>
<Con>2</Con>
<Cun>3</Cun>
<Dex>4</Dex>
<Mag>5</Mag>
<Per>6</Per>
<Str>7</Str>
<Wil>8</wil>
</stats>
</Character>
You have some typeo as well as some parsing errors.
Note that :
getElementsByTagName().toUpperCase is invalid because gEBTN returns array of objects. so, you have to use getElementsByTagName()[i].innerHTML.toUpperCase().
instead of using console.log("muuttujan x eka: " + x[0]);, use console.log("muuttujan x eka: " + x[0].innerHTML);
function load() {
var xmlhttp;
xmlhttp = new XMLHttpRequest();
var idname = document.getElementById("name").value;
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
console.log(xmlhttp); //it obtains it here...
LoadXML(xmlhttp, idname);
}
};
xmlhttp.open("GET", "helper_database.xml", false);
//xmlhttp.overrideMimeType('text/xml');
xmlhttp.send();
}
function LoadXML(xml, name) {
var x, i, xmlDoc, nametxt, areEqual;
xmlDoc = xml.responseXML;
nametxt = name;
console.log("HERE \n" + xmlDoc); //...but it becomes null.
x = xmlDoc.getElementsByTagName("name"); //this returns the error of "Cannot read property 'getElementsByTagName' of null"
console.log("muuttujan x eka: " + x[0].innerHTML);
for (i = 0; i < x.length; i++) {
if (areEqual = xmlDoc.getElementsByTagName("name")[0].innerHTML.toUpperCase() === nametxt.toUpperCase()) {
document.getElementById("ComFocus").value = x[i];
}
}
}
<html>
<body>
<input id="name" onblur="load();" />
<div id="ComFocus"></div>
</body>
</html>
XML
<?xml version="1.0" encoding="UTF-8"?>
<Character><name>test</name>
<stats>
<Com>1</Com>
<Con>2</Con>
<Cun>3</Cun>
<Dex>4</Dex>
<Mag>5</Mag>
<Per>6</Per>
<Str>7</Str>
<Wil>8</Wil>
</stats></Character>
The code below runs fine with a hard-coded tag name. I need to be able to call "loadDoc" with a variable that will return the tag I specify. I am rather new to JQuery and I'm not sure how to accomplish this.
Many thanks.
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
myFunction(xhttp);
}
}
xhttp.open("GET", "pyg280c.xml", true);
xhttp.send();
}
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var htext = "";
var x = xmlDoc.getElementsByTagName("PYP280CR");
for (i = 0; i <x.length; i++) {
htext += "<p>" + x[i].getElementsByTagName("PCST")[0].childNodes[0].nodeValue + "</p>";
}
document.getElementById("helptext").innerHTML = htext;
}
Since you say it works fine when you hardcode the tag name then as #Hackerman said pass the tagname into the loadDoc function. Pass it on to the myFunction function and simply use the tag name variable in the getElementByTagName(tag) function (no quotes around variables). It should work.
function loadDoc(myTagName) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
myFunction(xhttp, myTagName);
}
}
xhttp.open("GET", "pyg280c.xml", true);
xhttp.send();
}
function myFunction(xml, tag) {
var i;
var xmlDoc = xml.responseXML;
var htext = "";
var x = xmlDoc.getElementsByTagName("PYP280CR");
for (i = 0; i <x.length; i++) {
htext += "<p>" + x[i].getElementsByTagName(tag)[0].childNodes[0].nodeValue + "</p>";
}
document.getElementById("helptext").innerHTML = htext;
}
FYI - You mentioned jQuery. There is no jQuery in your code. jQuery probably would have made this easier.
Jquery version including some default ajax error handling:
function loadDoc(tag){
$.ajax({
url: "pyg280c.xml",
type: "GET",
dataType: "xml",
success: function(xml){
var xmlDOC = $.parseXML(xml.responseXML);
var x = $(xmlDOC).find("PYP280CR");
var htexts = $.map(x, function(el, idx){
return $(el).find(tag).children()[0].val();
}
htext = htexts.join(" ");
$('#helptext').html(htext);
},
error: function (xhr, ajaxOptions, thrownError){
console.log('status = ' + xhr.status);
console.log('error = ' + thrownError);
}
}