Switch Images Based on external text file content - javascript

I'm trying read a text file and based on the contents of that text file, change the image on a webpage. I tried using the console log to get error messages back, however I'm not getting errors. The contents of the txt file is literally the name of the images I want to show. Below is my javascript and html code.
<!DOCTYPE html>
<html>
<meta charset="utf-8"/>
<script type="text/javascript">
window.onload = function(){
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "../HTML/Images/Bowl.txt", true);
console.log(txtFile);
txtFile.onreadystatechange = function() {
allText = txtFile.responseText;
lines = txtFile.responseText.split("\n"); // Will separate each line into an array
if (lines === 'GDogbowl.png'){
document.getElementById('myImage').src='../HTML/Images/GDogbowl.png'
}
else if (lines === 'YDogbowl.png') {
document.getElementById('myImage').src='../HTML/Images/YDogbowl.png'
}
else {
document.getElementById('myImage').src='../HTML/Images/RDogbowl.png'
}
}
}
</script>
<body>
<table class="centerTable" >
<tr>
<td>
<div class="imgContainer">
<div>
<img id="fullsize" />
<ul id="thumbs">
<img id="myImage" src= "../HTML/Images/RDogbowl.png" style="width:100px">
</ul>
</div>
<div class="imgButton">
<button id="Bowl" >Toggle Color</button>
</div>
</div>
</td>
</table>
</body>

You can't magicly pull data out of an array as if it were a string. To solve the issue, you'll have to loop through the array after you've split the lines. Something like this:
var xhr = new XMLHttpRequest();
var data = null;
xhr.open("GET", "../HTML/Images/Bowl.txt", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
data = xhr.responseText.split('\n');
for(var i=0; i<data.length; i++){
document.getElementById('myImage').src='../HTML/Images/'+data;
}
}
};
xhr.send();

You need to check for txtFile.readyState == 4 and txtFile.status == 200 in your readystatechange handler, and you also need to do txtFile.send().
You also need to reference each URL in the lines array separately. Here's an example with two ways to show the images:
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "../HTML/Images/Bowl.txt", true);
console.log(txtFile);
txtFile.onreadystatechange = function() {
if (txtFile.readyState == 4 && txtFile.status == 200) {
allText = txtFile.responseText;
lines = txtFile.responseText.split("\n"); // Will separate each line into an array
if (lines[0] === 'GDogbowl.png'){
document.getElementById('myImage').src='../HTML/Images/GDogbowl.png'
}
else if (lines[0] === 'YDogbowl.png') {
document.getElementById('myImage').src='../HTML/Images/YDogbowl.png'
}
else {
document.getElementById('myImage').src='../HTML/Images/RDogbowl.png'
}
// if you have several images, you need several image elements:
lines.forEach(function(imgUrl, i) {
var image = document.createElement("img");
img.src = imgUrl;
img.id = "myImage_" + i;
document.body.appendChild(img);
});
}
}
txtFile.send();

split returns an array, where each element contains a line. So use, lines[0] to access the first element, lines[1] to access the second and so on.
If you don't care about handling state changes of your xmlHTTPRequest, then you can use the onload event, rather than onstatechange. ( I think all modern browsers should support this by now)
And as others have alluded in their answers, if you only care about the first line item, and you are sure that the name in the file is always valid, then you can concatenate the strings to achieve your goal without all the if/else cases.
<!DOCTYPE html>
<html>
<meta charset="utf-8"/>
<script type="text/javascript">
window.onload = function(){
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "../HTML/Images/Bowl.txt", true);
console.log(txtFile);
txtFile.onload = function() {
allText = txtFile.responseText;
lines = txtFile.responseText.split("\n"); // Will separate each line into an array
document.getElementById('myImage').src="../HTML/Images/"+lines[0];
</script>
<body>
<table class="centerTable" >
<tr>
<td>
<div class="imgContainer">
<div>
<img id="fullsize" />
<ul id="thumbs">
<img id="myImage" src="../HTML/Images/RDogbowl.png" style="width:100px">
</ul>
</div>
<div class="imgButton">
<button id="Bowl" >Toggle Color</button>
</div>
</div>
</td>
</table>
</body>

Related

Updating a variable using Ajax

I'm not familiar with Ajax so I'm learning fast. I'd appreciate some help on displaying a variable
rdm = urandom.randint(10,100) //comes from a loop in micropython.
Here's what I've so far. The part of turning ON/OFF a LED is working. I just cannot get the variable to update every 2 seconds.
TIA
<html>
<head>
<title>ESP32-OLED
</title>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.js" type="text/javascript">
</script>
</head>
<body>
<div>
<h4>The ESP32 Update web page without refresh
</h4>
<br>
<p>LED State:
<strong>%s
</strong>
</p>
<p>RDM number:
<span id="rdm">0
</span>
</p>
<p>
<button onclick="window.location.href = '/?led=on'">ON
</button>
</p>
<p>
<button onclick="window.location.href = '/?led=off'">OFF
</button>
</p>
<br>
<a href="http://www.google.com">www.google.com
</a>
</div>
<script>
var txt = "jQuery Works";
var _rdm = rdm;
//wait for the page to fully load
//$(document).ready(function(){
// var txt = "jQuery Works";
// alert(txt)
//}
//);
setInterval(function() {
// Call a function repetatively with 2 Second interval
getData();
}, 2000);
//2000mSeconds update rate
function getData() {
var xhttp = new XMLHttpRequest();
var rdm = document.getElementById("rdm").value;
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//returns 4 when the server finishes streaming the response
document.getElementById("rdm").innerHTML = _rdm;
//return object whose id property matches the specified string
}
};
xhttp.send();
}
</script>
</body>
</html>```
<!DOCTYPE html>
<html>
<head>
<title>ESP32-OLED
</title>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.js" type="text/javascript">
</script>
</head>
<body>
<div>
<h4>The ESP32 Update web page without refresh
</h4>
<br>
<p>LED State:
<strong>OFF
</strong>
</p>
<p>RDM number:
<span id="rdm">0
</span>
</p>
<p>
<button onclick="window.location.href = '/?led=on'">ON
</button>
</p>
<p>
<button onclick="window.location.href = '/?led=off'">OFF
</button>
</p>
<br>
<a href="http://www.google.com">www.google.com
</a>
</div>
<script>
var asyncGetData = new Promise(getData)
asyncGetData.then(() => {
setTimeout(asyncGetData, 2000)
})
function getData(resolve) {
var xhttp = new XMLHttpRequest();
var rdm = document.getElementById("rdm").value;
alert("Test 123!!");
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//returns 4 when the server finishes streaming the response
document.getElementById("rdm").innerHTML = rdm;
resolve();
//return object whose id property matches the specified string
}
};
xhttp.send();
}
</script>
</body>
</html>
You should resolve xhr before calling interval/timeout, also you need to call method open
var asyncGetData = new Promise(getData)
function run () {
asyncGetData.then(d => {
console.log(d)
setTimeout(run, 2000)
})
}
run()
function getData(resolve) {
var xhttp = new XMLHttpRequest();
// var rdm = document.getElementById("rdm").value;
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//returns 4 when the server finishes streaming the response
document.getElementById("rdm").innerHTML = JSON.stringify(JSON.parse(this.responseText), false, 2);
resolve(this.responseText);
//return object whose id property matches the specified string
}
};
// you need to call open with the method an the api url
xhttp.open('GET', 'https://api.github.com/users/octocat')
xhttp.send();
}
<pre id="rdm"></pre>

Displaying json data from server in basic html table using for loop, javascript only, problem with for loop?

I have the following Javascript code:
var request = new XMLHttpRequest();
request.open("GET", "http://localhost:8080/CarSales/rest/cars", true);
request.onreadystatechange = function(){
if(request.readyState === XMLHttpRequest.DONE){
var status = request.status;
if (status === 0 || (status >= 200 && status < 400)){
var cars = JSON.parse(request.responseText);
var output = "";
for(var i in cars){
output ='<tr><td>'+cars[i].make+'</td><td>'+cars[i].model+'</td><td>'+cars[i].year+'</td> <td>'+cars[i].engine+'</td></tr>';
}
document.getElementById('table-body').innerHTML = output;
}else{
console.log("error");
}
}
};
request.send();
and the following HTML:
<!DOCTYPE html>
<html>
<head>
<script src="js/Q4.js"></script>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<table id="table">
<tr>
<th>Make</th>
<th>Model</th>
<th>Year</th>
<th>Engine</th>
</tr>
<tbody id="table-body"></tbody>
</table>
</body>
</html>
Currently it outputs the last object of the json data in the table correctly:
https://i.stack.imgur.com/V73pC.png
How do I get the JS code to output all json objects into the table? Perhaps by changing the for loop to iterate through the json data?
You have missed to append on every loop. just add after output += ""; its not appending that's the reason displaying only last loop value.
for(var i in cars){
output +='<tr><td>'+cars[i].make+'</td><td>'+cars[i].model+'</td><td>'+cars[i].year+'</td> <td>'+cars[i].engine+'</td></tr>';
}

Javascript not executing when loaded via XMLHttpRequest but does when loaded with jQuery.load

While converting a script to not require jQuery, I've discovered that if I load my content (a partial html page with html and javascript) via XMLHttpRequest, the javascript in the partial page does not work. But if I load the partial using jQuery.load, it does work.
I've tried digging through jQuery's load function to see if it's doing anything special and nothing jumped out at me. I've been banging my head against the wall and searching for an answer for a couple of days now to no avail.
What am I doing wrong/how can I make it work like it does when loaded with jQuery.load?
EDIT
I got the XMLHttpRequest method to work by splitting out out my javascript from the html in the fragment and loading the javascript using the suggested technique here: https://stackoverflow.com/a/11695198/362958. However, that still does not provide an explanation of why jQuery.load works. Is jQuery umtimately parsing the HTML and doing the same thing for any scripts it finds within the content it loads?
I've set up a plunker (https://plnkr.co/edit/wE9RuULx251C5ARnUbCh) with the following code that demonstrates the issue. Note: once you load the fragment with jQuery, it will continue to work and you'll have to restart the plunk for the XMLHttpRequest method to fail again.
index.html:
<!DOCTYPE html>
<html>
<head>
<script data-require="jquery#*" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h3>Buttons</h3>
<div>
<input type="button" value="Load with XMLHttpRequest" onclick="loadXMLDoc('ajaxContentDiv', 'fragmentToLoad.html');"> (Links do not work if loaded this way... Script from fragmentToLoad.html not loaded in DOM?) <br/><br/>
<input type="button" value="Load with JQuery" onclick="jQuery('#ajaxContentDiv').load('fragmentToLoad.html');"> (Links will work if loaded this way)
</div>
<br/>
<br/>
<br/>
<div id="ajaxContentDiv">Content will load here...</div>
</body>
</html>
script.js:
function loadXMLDoc(targetDivName, url) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
document.getElementById(targetDivName).innerHTML = xmlhttp.responseText;
}
}
};
xmlhttp.send();
}
fragmentToLoad.html:
<div id="divToBeUpdated">
<span id="stringBox">String here</span>
</div>
<br/>
<h3>Links</h3>
<div>
Link 1<br>
Link 2<br>
Link 3<br>
</div>
<script>
function updateDiv(string){
var stringBox = document.getElementById('stringBox');
stringBox.innerHTML = string;
}
</script>
You can use single .html file, and you are on the correct track by splitting the html content - though you can also split the html content of a single file, rather than requesting two files. #Barmar explains the functionality of jQuery's .load() method at this comment.
script.js
function loadXMLDoc(targetDivName, url) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", url, true);
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
// create a `div` elemenent, append response to `div` element
// get specific elements by `id`, append `script` element to `document.body`
var content = document.createElement("div");
content.innerHTML = xmlhttp.responseText
var div = content.querySelector("#htmlContent");
var contentScript = content.querySelector("#contentScript");
var script = document.createElement("script");
script.textContent = contentScript.textContent;
document.getElementById(targetDivName).innerHTML = div.innerHTML;
document.body.appendChild(script);
}
}
};
xmlhttp.send();
}
fragmentToLoad.html
<div id="htmlContent">
<div id="divToBeUpdated">
<span id="stringBox">String here</span>
</div>
<br/>
<h3>Links</h3>
<div class="links">
Link 1
<br>
Link 2
<br>
Link 3
<br>
</div>
</div>
<script type="text/javascript" id="contentScript">
function updateDiv(string) {
var stringBox = document.getElementById('stringBox');
stringBox.innerHTML = string;
}
// attach `click` event to `.link a` elements here
var links = document.querySelectorAll(".links a");
for (var i = 0; i < links.length; i++) {
(function(link, i) {
console.log(i)
link.addEventListener("click", function(e) {
e.preventDefault();
updateDiv("Hello World " + i)
})
})(links[i], i)
}
</script>
plnkr https://plnkr.co/edit/7fLtGRSV7WlH2enLbwSW?p=preview

Ajax doesn't work when I change document.getElementById

I have the following code which I found at W3Schools and when I use document.getElementById it works, when I change this to document.getElementsByClassName (on my full code, I will have more than <p class="txthint"> why I thought I should be using documents.getElementsByClassName) it just stops working.
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include file="Connections/PSCRM.asp" -->
<%
Dim Recordset1
Dim Recordset1_cmd
Dim Recordset1_numRows
Set Recordset1_cmd = Server.CreateObject ("ADODB.Command")
Recordset1_cmd.ActiveConnection = MM_PSCRM_STRING
Recordset1_cmd.CommandText = "SELECT prodref FROM dba.proditem where created >= '2015-08-01' and obsolete = '0' ORDER BY prodref asc"
Recordset1_cmd.Prepared = true
Set Recordset1 = Recordset1_cmd.Execute
Recordset1_numRows = 0
%>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
</head>
<body>
<form action="">
<input type="text" onChange="showCustomer(this.value)" value="">
</form>
<br>
<div class="txtHint">Customer info will be listed here...</div>
<script>
function showCustomer(str) {
var xhttp;
if (str == "") {
document.getElementsByClassName("txtHint").innerHTML = "";
return;
}
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 200) {
document.getElementsByClassName("txtHint").innerHTML = xhttp.responseText;
}
}
xhttp.open("GET", "data.asp?prodref="+str, true);
xhttp.send();
}
</script>
</body>
</html>
<%
Recordset1.Close()
Set Recordset1 = Nothing
%>
getElementsByClassName returns a collection of nodes, not a single node. You need to iterate that collection and set the innerHTML property on each node:
var nodes = document.getElementsByClassName("txtHint");
for (var i = 0; i < nodes.length; i++)
nodes[i].innerHTML = '';
Your current code is setting the property on the collection itself which, as it's perfectly valid JavaScript, doesn't error, but causes nothing to update either - it's just now the node collection has an unused innerHTML property.
If you look at the documentation for getElementsByClassName, you'll notice that you are returning an array of object whereas getElementById returns a single element.
With the array, there is no prototype for innerHtml, this is only exposed on a single element.
What you will need to do is iterate through the list of elements you retrieve from the getElementsByClassName.
var elements =document.getElementsByClassName("txtHint");
for(var i = 0; i < elements.length; i++){
elements[i].innerHTML = xhttp.responseText
};
Try that and see if it helps

use Ajax and JavaScript to create dynamic links from the results

HTML contains two div make different ajax calls to both the divs,where div1 is the result of html form and div2 should be the result of onclick on div1
html
<html lang="en">
<head>
<title>Display Movie Information</title>
<meta charset="utf-8"/>
<script type="text/javascript" src="movies.js"></script>
</head>
<body onload="initialize();">
<tr><td>
<form>
<label>Movie title: <input type="text" id="form-input"/></label>
<input type="button" onclick="sendRequest();" value="Display Info"/>
</form>
<div id="output"> </div></td>
<td><div id="right_panel">Display Dynamic results here</div></td>
</body>
</html>
I have a movies.js file which using ajax gets the result
function initialize () {
}
function sendRequest () {
var xhr = new XMLHttpRequest();
var query = encodeURI(document.getElementById("form-input").value);
xhr.open("GET", "proxy.php?method=/3/search/movie&query=" + query);
xhr.setRequestHeader("Accept","application/json");
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
var json = JSON.parse(this.responseText);
var str = JSON.stringify(json,undefined,2);
//customized code
console.log(json.results.length);
var i=0;
var movie_title,release_date;
var movies = new Array();
while(i<json.results.length)
{
movie_title = json.results[i].title;
release_date = json.results[i].release_date;
movies[i] = "<li>"+movie_title+"<br/>"+release_date+"<br/></li>";
i++;
}
document.getElementById("output").innerHTML = "<ul>" + movies + " </ul>";
}
};
var movie_detail = new XMLHttpRequest();
var movie_credit = new XMLHttpRequest();
xhr.send(null);
}
This code displays the title and the release date of the movies(result of onclick on the button)
Q: I want to make the movie title an hyperlink that could make a call like www.imdb.com/(movie_title) and display the result in the second div tag named "right_panel" using only ajax and javascript and no jquery.

Categories