I am using Js xmlHttpRequest to display the same menu on different pages of my site. Lately I found out that some functions are not executed when the site is online, like a quiz I made.
I had also tried to use fetch, or put the scripts in different files, but the same thing kept happening.
(The quiz does work when checking locally, where the xml request cannot be satisfied.)
//load the menu
onload = function loadXMLDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementsByTagName('body')[0].innerHTML +=
this.responseText;
}
};
xhttp.open("GET", "mnu.html", true);
xhttp.send();
}
//check the quiz
const checkBtn = document.getElementById('checkBtn')
checkBtn.onclick = function quizCheck() {
//right answers
var score = 0;
if (q1a1.checked) {
score = score + 1;
}
if (q2a1.checked) {
score = score + 1;
}
alert("your score: " + score);
}
<li>
Check the right answer:
<br>
<input type="checkbox" id="q1a1">Right
<br>
<input type="checkbox">Wrong
</li>
<li>
Check the right answer:
<br>
<input type="checkbox" id="q2a1">Right
<br>
<input type="checkbox">Wrong
</li>
<button id="checkBtn">Check</button>
Anybody knows why and/or has some solutions?
The problem is this line which is wrong and that's why js is not working.
document.getElementsByTagName('body')[0].innerHTML += this.responseText;
You can't just add to innerHtml like that.
Instead you should create an html element and add it to body like this:
if (this.readyState == 4 && this.status == 200) {
var p = document.createElement("p");
p.innerText = this.responseText;
document.body.appendChild(p);
}
edit: of course you want to add an html menu instead of just a text inside a <p>, so you will have to add it like this:
var nav = document.createElement('nav');
nav.innerHTML = this.responseText;
document.body.prepend(nav); // always at the top
Related
I'm still learning a lot about web development and javascript, so forgive me if my explanations are not clear.
I have a function to request from an API informations about cryptocurrency (Price, volume etc.) in a JSON file and then i display the price on the web page every 15 seconds.
I want to change the background color of the card where the price is displayed by comparing the actual price and the new one coming from the next request.
here's my javascript :
function requestPrice(url, domLocation){
var req = new XMLHttpRequest();
req.open("GET", url);
req.addEventListener("load", function() {
if (req.status >= 200 && req.status < 400) {
var data = JSON.parse(req.responseText)
domLocation.innerHTML = data.ticker.price + "$";
erreur.innerHTML = "";
} else {
erreur.innerHTML = "Erreur: " + req.status + " " + req.statusText;
}
});
req.addEventListener("error", function () {
erreur.innerHTML = "Erreur";
});
req.send(null);
}
var btcPrice = document.getElementById('boxBTC'), erreur =
document.getElementById('erreur');
setInterval(requestPrice("https://api.cryptonator.com/api/ticker/btc-eur",
btcPrice), 15000);
I was thinking of a simple comparaison between the values and put this code in my loop but i need to stock the actual price somewhere to do the comparison with the new one coming and i'm stuck with that.
if (valueOf(data.ticker.price) <= valueOf(data.ticker.price)){
document.getElementById('overviewcard').style.backgroundColor = red;
} else {
document.getElementById('overviewcard').style.backgroundColor = blue;
}
Or
var overviewcard = getElementById('overviewcard');
if (data.ticker.price <= data.ticker.price){
overviewcard.style.backgroundColor = red;
} else {
overviewcard.style.backgroundColor = blue;
}
here's the html :
<div class="overviewcard">
<span id="boxBTC">...</span>
<span id="erreur"></span>
</div>
Thanks a lot for your help
You can do this in a myriad of ways, but the simplest is to grab the data from the actual HTML DOM element.
var currValue = document.getElementById('boxBTC').innerHTML;
if(valueOf(data.ticker.price) == currValue) {
// do something
}
If you're boxBTC string is formatted too much (eg. if you make "1000" -> "1,000"), then you can always also store a data attribute of the raw value inside the DOM as a data attr.
// assigning the data
document.getElementById('boxBTC').setAttribute('data-val', price);
...
// accessing the data
document.getElementById('boxBTC').getAttribute('data-val');
I have a function that is responsible for updating the values in some <div>, the code looks like this:
file.js
window.onload = function makeRequest() {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
calcPreco(xmlHttp.responseText);
}
xmlHttp.open("GET", "_config/buscar_valor.php?id="+document.getElementsByName("cloud")[0].getAttribute("cloudid")+"&periodicidade=monthly", true); // true para asynchronous
xmlHttp.send(null);
}
function calcPreco(preco) {
console.log(preco);
preco = preco.replace(",", ".");
preco -= document.getElementsByName("cloud")[0].getAttribute("desconto");
document.getElementsByClassName("mostrar_valor").textContent = preco;
}
index.php
<div name="cloud" cloudid="1" desconto="5">
<span class="mostrar_valor"></span>
</div>
<div name="cloud" cloudid="2" desconto="10">
<span class="mostrar_valor"></span>
</div>
<div name="cloud" cloudid="3" desconto="15">
<span class="mostrar_valor"></span>
</div>
Note that only the cloudid anddesconto attributes are changed in each <div>, the remainder remains the same.
The script will only do a calculation by searching for the value in "buscar_valor.php", through the cloudid attribute, which is the ID of each plan.
The desconto attribute is the amount it will subtract from the account.
The problem is that it is doing this only for the first <div>, how can I make it work for all <div>?
You have to loop over all cloud elements as:
for(const cloud of Array.from(document.getElementsByName("cloud"))) {
To then retrieve the related preco from the API I would use the new fetch method as that is way more easy to handle:
fetch("_config/buscar_valor.php?id=" + cloud.getAttribute("cloudid")+ "&periodicidade=monthly")
.then(res => res.text())
.then(preco => {
Now the desconto can be applied to preco:
preco -= cloud.getAttribute("desconto");
To get the mostrar_valor insode that cloud, just use querySelector:
const valor = cloud.querySelector(".mostrar_valor");
then you can change the textContent of that element.
The java script only get the first id. The 2nd id ignores the code. Are there anyway to make both IDs using the same java script ?
Add Item
List Items
<div id="add_item" class="tabcontent">
<div id="subcatchooser"></div>
<div id="list_item" class="tabcontent">
<div id="subcatchooser"></div>
Java Script here
function showsubcat(str) {
if (str.length == 0) {
document.getElementById("subcatchooser").innerHTML = "";
return;
} else {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("subcatchooser").innerHTML = this.responseText;
}
};
xmlhttp.open("GET", "ajax.php?action=showsubcat&parent_id=" + str, true);
xmlhttp.send();
}
}
</script>
That is the main difference between classes and IDs. Classes are designed to be used multiple times, while IDs are designed to be unique. So you can change the divs to look like this:
<div class="subcatchooser"></div>
And then change the JavaScript to look like this:
var elements = document.getElementsByClassName("subcatchooser");
for (var i = 0; i < elements.length; i++) {
elements[i].innerHTML = "";
}
Currently, when a div is clicked, jQuery detects it sends request to fetch data from mysql via Ajax.
What I'm actually fetching is, sub categories for the item clicked and display them in html page.
Now all is done in procedural way, so when another sub level needed to be displayed, I have to copy paste the ajax function. But how do make it into objects so that I don't have to repeat myself?
I just need to know how to bring in OOP into this context..Any help will be greatly appreciated. Thank you.
HTML
<!--append the default top level items starts-->
<div id="default"></div>
<!--append the default top level items ends-->
<hr>
<!--append the default top level items starts-->
<div id="sub"></div>
<!--append the default top level items ends-->
Jquery/AJax
<!--select top level items and append to default id starts-->
$("#clickme").on("click",function()
{
var xmlhttp = getXmlHttp();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
if (this.responseText !== null) {
var data = JSON.parse(this.responseText);
//console.log(this.responseText);
//console.log(JSON.parse(this.responseText));
for (i = 0; i < data.length; i++)
{
var id=data[i].id;
var name=data[i].item_name;
/*check if sub item exist*/
checkSubExist(id);
/*append to div*/
$("#default").append("name= "+name+", ");
}
}
}
}
xmlhttp.open("GET", "selectTopLevel.php");
xmlhttp.send();
});
<!--select top level items and append to default id ends-->
function checkSubExist(param)
{
//alert(param);
var xmlhttp = getXmlHttp();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
if (this.responseText !== null) {
var data = JSON.parse(this.responseText);
//console.log(this.responseText);
//console.log(JSON.parse(this.responseText));
for (i = 0; i < data.length; i++)
{
var id=data[i].id;
var name=data[i].item_name;
//alert(name);
$("#sub").append(name+", ");
}
}
}
}
xmlhttp.open("GET", "checkSubExist.php?sub="+param);
xmlhttp.send();
}
I would use $.ajax to wrap the xmlHttpRequest.
If you want a more "OOP" like approach, I would suggest you define some kind of Request Wrapper Objects which you then create upon event binding, naive example:
var RequestWrapperProto = {
getSubnodes: function(){
//handle request
}
//etc
}
var requestWrapper = Object.create(RequestWrapperProto)
$('.sub').on('click', requestWrapper.getSubNodes);
I'm not one of those people that grew up with programming, or have experienced in high school. I just recently started the basics in College. What I have below is my javascript/html that I have been working on Visual Studio 2012. My goal for it is to display the images one at a time by pressing a button called "Next Name" (as you can see I created a "form" at the bottom of my code). But as I have it now, it prints out all the images in my "hw1.txt" at the same time. Under my for loop, I tried "result = "";" and then "displayList.innerHTML = result;" hoping to just print out one image at least. I tried other things, but it just left my code messy. Please I need help. Any advice, pointers, or whatever is good. Can you also explain your answers in a way that I'll understand too? Just think of me as you're talking to a child or something haha. Thanks.
Note: in "hw1.txt" every 3rd index (starting from index 0) is the name of people, and the index next to it (myArray[i + 1]) is the image file (inside the .txt it goes like 1.jpg, 2.jpg, 3.jpg, and so on...)
<br/>
<span id="displayList">Photo here.</span>
<script type=text/javascript>
if (typeof ActiveXObject != "undefined") // IE
var req = new ActiveXObject("Microsoft.XMLHTTP");
else // Other browsers
var req = new XMLHttpRequest();
req.open('GET', 'hw1.txt', false);
req.send(null);
s = req.responseText;
var myArray = s.split(";");
var result = "";
function nextItem() {
for (i = 3; i < myArray.length; i = i + 3)
result = result + "<img src='" + myArray[i + 1] + "'/>";
displayList.innerHTML = result;
}
</script>
<form name="ClickNext">
<input type="button" value="Next Name" onclick="nextItem()" />
</form>
<span id="displayList">Photo here.</span>
<script type=text/javascript>
if (typeof ActiveXObject != "undefined") // IE
var req = new ActiveXObject("Microsoft.XMLHTTP");
else // Other browsers
var req = new XMLHttpRequest();
req.open('GET', 'hw1.txt', false);
req.send(null);
s = req.responseText;
var myArray = s.split(","); //if images are comma(,) seperated then just split it from comma
var index = 0;
function nextItem() {
if(typeof myArray[index] !== 'undefined') {
displayList.innerHTML = "<img src='" + myArray[index] + "'/>";
index += 1;
}
}
</script>
<form name="ClickNext">
<input type="button" value="Next Name" onclick="nextItem()" />
</form>
First off you don't need the form around that input since you don't really send a form.
Secound you should add an id to your input ( or <a></a> or <button></button> ) such as id="next_name" or I guess you can keep the old way of calling an event. :P
Then, you should:
var position = 0;
var result = '';
document.getElementById('next_name').onclick = function(){
if(position < myArray.length){
result = result + "<img src='" + myArray[position + 1] + "'/>";
displayList.innerHTML = result;
position++;
}
};
The idea is to use a variable to memorize your position within your list of image srouces. Once you use one, you increment your position within the list so next time a user clicks that button you add a different image.