I have a small data store of quotes like this:
let quotes = [{
quote: "Search others for their virtues, thyself for thy vices.",
source: "Benjamin Franklin",
citation: "Poor Richard\'s Almanac",
category: "ethics",
year: ''
}, {
quote: "He who has courage despises the future.",
source: "Napoleon Bonaparte",
citation: '',
category: "boldness",
year: ''
}
]
I am running a simple javascript function to change the html based on the data store with this:
const getRandomQuote = () => {
let quoteShownArr = [];
let quoteIndex = Math.floor((Math.random() * quotes.length) + 1);
for (let i = 0; i < quotes.length; i++) {
if (quoteIndex === i) {
document.getElementsByTagName("P")[0].innerHTML = quotes[i].quote;
document.getElementsByTagName("P")[1].innerHTML = quotes[i].source;
let citation = quotes[i].citation;
if(citation) {
console.log(citation);
document.getElementById("citation").innerHTML = quotes[i].citation;
}
document.getElementById("year").innerHTML = quotes[i].year;
}
}
}
getRandomQuote();
All the html elements are being updated except for my citation and year, which are span elements. I get the following error:
TypeError: "Cannot set property 'innerHTML' of null
at getRandomQuote" But the exact value consoles easily. How is this not changing the element??
Thanks.
HTML added:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Random Quotes</title>
<link href='https://fonts.googleapis.com/css?family=Playfair+Display:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<div class="container">
<div id="quote-box">
<p class="quote">You can do anything but not everything</p>
<p class="source">David Allen<span class="citation" id="citation">Making It All Work</span><span class="year" id="year">2009</span></p>
</div>
<button id="loadQuote">Show another quote</button>
</div>
<script src="js/script.js"></script>
</body>
</html>
in this line
document.getElementsByTagName("P")[1].innerHTML = quotes[i].source;
you set the inner html to the source text, removing all other html content e.G your spans, this is why they are null because they dont exist anymore
Related
i created an array and insert elements by array.push(). when i console.log(array) it gives me following out put output of console.log(array)
when i console.log(array[0]) it gives me undefined. why is happing and a blue i tag appear in picture which says "this value was evaluated on first expanding it may have changed since then in array javascript" what does means. please help me to understand the problem
here the full code
index.html =>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>zip reader</title>
</head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />
<script type="text/javascript" charset="utf8" src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/jstree.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
<body>
<h3>Choose the local(s) zip file(s)</h3>
<input type="file" id="file" name="file" multiple /><br />
<div id="result_block" class="hidden">
<h3>Content :</h3>
<div id="result">
</div>
</div>
</body>
<script src="jszip.min.js"></script>
<script src="jszip-utils.min.js"></script>
<script src="app1.js"></script>
<script src="FileSaver.min.js"></script>
</html>
app1.js =>
var array = []
var contents = []
var $result = $("#result");
$("#file").on("change", function(evt) {
// remove content
$result.html("");
// be sure to show the results
$("#result_block").removeClass("hidden").addClass("show");
// Closure to capture the file information.
function handleFile(f) {
var $title = $("<h4>", {
text : f.name
});
var $fileContent = $("<ul>");
$result.append($title);
$result.append($fileContent);
var dateBefore = new Date();
JSZip.loadAsync(f) // 1) read the Blob
.then(function(zip) {
var dateAfter = new Date();
$title.append($("<span>", {
"class": "small",
text:" (loaded in " + (dateAfter - dateBefore) + "ms)"
}));
zip.forEach( function (relativePath, zipEntry) {
var y = zipEntry.name
array.push(y);
$fileContent.append($("<li>", {
text : zipEntry.name
}));
});
}, function (e) {
$result.append($("<div>", {
"class" : "alert alert-danger",
text : "Error reading " + f.name + ": " + e.message
}));
});
}
var files = evt.target.files;
for (var i = 0; i < files.length; i++) {
handleFile(files[i]);
}
console.log(array[0])
});
When you console.log an object (including arrays), it isn't being serialized, and only a reference is passed to a console. When you expand it, this reference is used to check the state of this object.
Most probably what's happening is the following sequence:
console.log(array) // passes array reference to a console
console.log(array[0]) // prints undefined immediately
array.push(...) // an actual array modification
you expand the object, and console checks the content of an array
PS.
It's reasonable to ask, what will happen, if the reference will become invalid due to any reason.
For browsers - it's simpler, since the console and JS program run under same parent process, browser is responsible for everything.
But if you'll ever try to debug Node process, which has the same API of passing the reference, you will face strange issues all over around, like this one: No debug adapter, can not send 'variables VSCODE
I am very new to coding and couldn't find solution with if condition for this.
I know how I can do it with html code and options, but this time I need to make it with arrays and if function.
Basically I just need a dropdown with languages (which I made) and then when I click on specific language (for example, English) - I need to change html h1 to "Hello!", when I click Latvian "Labdien" etc.
Basically I need to write a proper if function, hope you could tell me what's wrong there.
const select = document.getElementById("select"),
arr = ["Latvian", "English", "Russian"];
for (var i = 0; i < arr.length; i++) {
var option = document.createElement("OPTION"),
txt = document.createTextNode(arr[i]);
option.appendChild(txt);
option.setAttribute("value", arr[i]);
select.insertBefore(option, select.lastChild);
}
if (arr[0] = "Latvian") {
document.getElementById("heading").innerHTML = "Labdien!";
} else if (arr[1] == "English") {
document.getElementById("heading").innerHTML = "Hello!";
} else if (arr[2] == "Russian") {
document.getElementById("heading").innerHTML = "Добрый день!";
}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Dropdown</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1 class="heading" id="heading"></h1>
<select class="drop" id="select"></select>
<script src="./main.js"></script>
</body>
Still figuring out whats wrong with if statement, there is some problem in :
if(arr[0] == "Latvian")
else if(arr[1] == "English")
else if(arr[2] == "Russian").
Or maybe I need to call a function and then place it onchoice in HTML? Help.. been googling and youtubing all day
You can add a change event listener to the select element. Also, you can use the index of each language as the value of the select options, and use the same array when set the h1 inner HTML:
var select = document.getElementById("select");
var arr = [
{ id: 1, language: 'Latvian', title: 'Labdien!' },
{ id: 2, language: 'English', title: 'Hello!' },
{ id: 3, language: 'Russian', title: 'Добрый день!' }
];
for (var i = 0; i < arr.length; i++) {
var option = document.createElement("OPTION");
var txt = document.createTextNode(arr[i].language);
option.appendChild(txt);
option.setAttribute('value', arr[i].id);
select.insertBefore(option, select.lastChild);
}
// add a change event listener to handle the language title
select.addEventListener('change', changeHeading);
// trigger a change event in order to display the selected language's title
select.dispatchEvent(new Event('change'));
function changeHeading(event) {
var language = arr.find(
(language) => language.id === parseInt(event.target.value)
);
document.getElementById('heading').innerHTML = language.title;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Dropdown</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h1 class="heading" id="heading"></h1>
<select class="drop" id="select"></select>
<script src="./main.js"></script>
</body>
</html>
I have 2 html files connected to one js file. When I try to access a html element in the second html file using js it doesn't work saying that is is null. I did
let elementname = document.getElementById("element") for a element in the second html page then
console.log(elementname) and it says it is null. When I do it for a element in the first html page it says HTMLButtonElement {}
Here is the html for the first Page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Not Quuuuiiiizzzz</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<h1>Not Quuuuiiiizzzz</h1>
<h2>Join a quiz</h2>
<!--Buttons -->
<div style="text-align: center;">
<button id="btnforquiz1" onclick="gotoquiz()"></button>
<button id="btnforquiz2" onclick="gotoquiz1()"></button>
<button id="btnforquiz3" onclick="gotoquiz2()"></button>
</div>
<h2 id="h2">Create a Quuuuiiiizzzz</h2>
<script src="script.js"></script>
</body>
</html>
For the second page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Not Quuuuiiiizzzz</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body onload="quizLoad()">
<h1 id="question">Hello</h1>
<button id="answer1"></button>
<button id="answer2"></button>
<button id="answer3"></button>
<button id="answer4"></button>
<script src="script.js"></script>
</body>
</html>
And Finally for the js file :
//setting global variables
let btn1 = document.getElementById("btnforquiz1") //getting button with id of btnforquiz1 repeat below
correct = 0
let btn2 = document.getElementById("btnforquiz2")
let btn3 = document.getElementById("btnforquiz3")
let question = document.getElementById("question")
let answer1 = document.getElementById("answer1")
let answer2 = document.getElementById("answer2")
let answer3 = document.getElementById("answer3")
let answer4 = document.getElementById("answer4")
quizNameRel = -1;
cosnole.log(question)
console.log(answer1)
//Quiz Data
Quiz_1 = {
"What is the capital of buffalo":["Idk", "Yes", "No",0],
"What is the smell of poop": ["Stinky"]
};
Quiz_2 = [
"What is wrong with you"
];
Quiz_3 = [
"What is wrong with you #2"
]
let quiz = {
name: ["History Test", "Math Practice", "ELA Practice"],
mappingtoans: [0,1,2],
QA: [Quiz_1, Quiz_2, Quiz_3]
}
//quiz data
//when body loades run showQuizzs function
document.body.onload = showQuizzs()
function showQuizzs() {
//loops throo the vals seeting the text for the btns
for (let i = 0; i < quiz.name.length; i++) {
btn1.textContent = quiz.name[i-2]
btn2.textContent = quiz.name[i-1]
btn3.textContent = quiz.name[i]
}
}
//leads to the showQuizzs
function gotoquiz() {
location.href = "quiz.html"
quizNameRel = quiz.name[0]//I was trying to create a relation so we could knoe which quiz they wnt to do
startQuiz()
}
function gotoquiz1() {
location.href = "quiz.html"
quizNameRel = quiz.name[1]
startQuiz()
}
function gotoquiz2() {
location.href = "quiz.html";
quizNameRel = quiz.name[2];
startQuiz();
}
function answerselect(elements){
whichone = Number(elements.id.slice(-2,-1))
if(Quiz_1[whichone]==Quiz_1[-1]){
correct+=1;
NextQuestion();
}else{
wrong+=1;
}
}
//gets the keys and puts it into an array
function getkeys(dictionary){
tempdict = [];
for(i in dictionary){
tempdict.push(i);
}
return tempdict;
}
function setQuestion() {
let tempdict = getkeys(Quiz_1)
console.log(tempdict, getkeys(Quiz_1));
//question.innerHTML = tempdict;
}
// startQuiz
function startQuiz() {
switch (quizNameRel){
case quiz.name[0]:
//case here
setQuestion()
break
case quiz.name[1]:
//case here
break
case quiz.name[2]:
//case here
break
}
}
//TO DO:
// Set the question
// Set the answer
// Check if correct button
This is happening because at a time you have rendered only one html file. For example if you render index1.html(first file) then your js will look for rendered element from first file only but here index2.html(second file) is not rendered so your js script is unable to find elements of that file that's the reason it shows null.
If you try to render now index2.html rather than index1.html then you will find now elements from index2.html are detected by js script but elements from index1.html are null now.
I have written this code which I thought was correct, but although it runs without error, nothing is replaced.
Also I am not sure what event I should use to execute the code.
The test a simple template for a landing page. The tokens passed in on the url will be used to replace tags or tokens in the template.
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
// gets passed variables frm the url
function getQueryVar(str) {
return 'Newtext'; // JUST SCAFFOLD FOR TESTING
}
function searchReplace() {
/**/
var t = 0;
var tags = Array('keyword', 'locale', 'advert_ID');
if (document.readyState === 'complete') {
var str = document.body.innerText;
for (t = 0; t < tags.length; t++) {
//replace in str every instance of the tag with the correct value
if (tags[t].length > 0) {
var sToken = '{ltoken=' + tags[t] + '}';
var sReplace = getQueryVar(tags[t]);
str.replace(sToken, sReplace);
} else {
var sToken = '{ltoken=' + tags[t] + '}'
var sReplace = '';
str.replace(sToken, sReplace);
//str.replace(/sToken/g,sReplace); //all instances
}
}
document.body.innerText = str;
}
}
</script>
</head>
<body>
<H1> THE HEADING ONE {ltoken=keyword}</H1>
<H2> THE HEADING TWO</H2>
<H3> THE HEADING THREE</H3>
<P>I AM A PARAGRAPH {ltoken=keyword}</P>
<div>TODO write content</div>
<input type="button" onclick="searchReplace('keyword')">
</body>
</html>
So when the documment has finished loading I want to execute this code and it will replace {ltoken=keyword} withe value for keyword returned by getQueryVar.
Currently it replaces nothing, but raises no errors
Your problem is the fact you don't reassign the replacement of the string back to it's parent.
str.replace(sToken,sReplace);
should be
str = str.replace(sToken,sReplace);
The .replace method returns the modified string, it does not perform action on the variable itself.
Use innerHTML instead innerText and instead your for-loop try
tags.forEach(t=> str=str.replace(new RegExp('{ltoken='+ t+'}','g'), getQueryVar(t)))
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
// gets passed variables frm the url
function getQueryVar(str)
{
return'Newtext';// JUST SCAFFOLD FOR TESTING
}
function searchReplace() {
/**/
var t=0;
var tags =Array('keyword','locale','advert_ID');
if (document.readyState==='complete'){
var str = document.body.innerHTML;
tags.forEach(t=> str=str.replace(new RegExp('{ltoken='+ t+'}','g'), getQueryVar(t)));
//tags.forEach(t=> str=str.replace(new RegExp('{ltoken='+ tags[t]+'}', 'g'), getQueryVar(tags[t])));
document.body.innerHTML=str;
}
}
</script>
</head>
<body >
<H1> THE HEADING ONE {ltoken=keyword}</H1>
<H2> THE HEADING TWO</H2>
<H3> THE HEADING THREE</H3>
<P>I AM A PARAGRAPH {ltoken=keyword}</P>
<div>TODO write content</div>
<input type ="button" onclick="searchReplace('keyword')" value="Clicke ME">
</body>
</html>
Why does this work
app.prints(address,list.options[list.selectedIndex].value);
but this doesn't?
app.prints(status,macAddress);
JavaScript
var hey = 5;
var app = {
createList: function () {
for (var i = 0; i < 5; i++) {
list.options[i] = new Option(hey + i, "mac" + i);
}
app.prints(address, list.options[list.selectedIndex].value);
},
prints: function (location, message) {
location.innerHTML = message;
},
manageConnection: function () {
var macAddress = list.options[list.selectedIndex].value;
app.prints(status, macAddress);
}
}
HTML
<!DOCTYPE html>
<!-- Don't panic! All this
code looks intimidating but eventually it will make sense. -->
<html lang="en">
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="text/javascript" src="ECMA.js"></script>
<title>My LCD code</title>
</head>
<body onload="app.initialize();">
<p>Welcome to the LCD software</p>
<select id="list" onchange="app.prints
(address,list.options[list.selectedIndex].value);"></select>
<div id="address"></div>
<button id="connect" onclick="app.manageConnection();">Connect</button>
<div id="status">hi</div>
</body>
</html>
The difference is that a global status variable has already been defined by the browser to represent the text in the status bar. And, browsers don't allow a reference to the element to replace it.
To avoid the naming conflict, you can rename the element.
But, you really shouldn't depend on automatic globals for ids. Not all browsers implement the feature, and some only in certain modes.
var list = document.getElementById('list');
var address = document.getElementById('address');
app.prints(address, list.options[list.selectedIndex].value);