I'm running my code in node.js I've seen that running code in node could play a part. But this was never a problem. It keeps saying my variable that points to my element 'document is not defined'. I don't know what I'm doing wrong, I'm linking it correctly but still confused I also tried putting my scripts on the bottom and top with defer.
let seconds = 00;
let tens = 00;
let appendTens = document.querySelector('#tens');
let appendSeconds = document.querySelector('#seconds');
let stop = document.querySelector('#button-stop');
let start = document.querySelector('#button-start');
let reset = document.querySelector('#button-reset');
let interval; //store timer values
// this function will run when start is clicked
const startTimer = () =>{
tens++
if(tens < 9){
appendTens.textContent = `0${tens}`
}
if(tens > 9){
appendTens.textContent = tens;
}
if(tens > 99){
seconds++
appendSeconds.textContent = `0${seconds}`;
tens = 0;
appendTens.textContent = "0" + 0;
}
if(seconds > 9){
appendSeconds.textContent = seconds;
}
};
start.onclick = function(){
interval = setinterval(startTimer)
}
<!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>Stopwatch</title>
<link rel="stylesheet" href="stopwatch.css">
</head>
<body>
<div class="wrapper">
<h1>Stopwatch</h1>
<h2>Vanilla JavaScript Stopwatch</h2>
<p><span id="seconds">00</span>:<span id="tens">00</span></p>
<button id="button-start">Start</button>
<button id="button-stop">Stop</button>
<button id="button-reset">Reset</button>
</div>
<script type="module" src="stopwatcj.js"></script>
</body>
</html>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-self: center;
background-color: rgb(248, 180, 55);
}
.wrapper {
margin-top: 10%;
text-align: center;
color: #fff;
}
.wrapper button {
background-color: rgb(248, 180, 55);
border: 1px solid white;
padding: 10px 20px;
color: #fff;
}
.wrapper button:hover {
cursor: pointer;
opacity: 30%;
}
document which is a part of Html DOM is not a part of nodejs. Since you might be using nodejs to compile your js code that's why you are getting this error. Please try to run this simply in browser.
Related
I'm working on a portfolio project - which should use jquery - part of the task is to set and get text via localstorage - which I can do in Javascript but I breaks when attempting to refactor in jquery.
I found an elegantly simple javascript codepen, which has all the features I want. But when I refactor into jquery it loses funtionality - I can't save the text to local storage (I get null) and I can't copy the text to a different Div.
This is the 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">
<link rel="stylesheet" href="style.css">
<title>Local Test</title>
</head>
<body>
<div class="content-output"></div>
<textarea class="content-input" placeholder="Your text here"></textarea>
<button class="save-button">Save</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="./script.js"></script>
</body>
</html>
This is simple CSS from the JS code pen:
* {
font-size: 16px;
font-family: sans-serif;
}
body {
padding: 1rem;
font-family: sans-serif;
}
.content-output {
float: left;
box-sizing: border-box;
background: #f9f9f9;
padding: 0.5rem;
width: calc(50% - 1rem);
height: 10rem;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
color: #202020;
}
.content-input {
float: left;
box-sizing: border-box;
margin-left: 2rem;
padding: 0.5rem;
width: calc(50% - 1rem);
height: 10rem;
border: 1px solid #505050;
resize: none;
}
.save-button {
/* -webkit-appearance: none; */
border: 0;
background: #0088ff;
padding: 0.5rem 1rem;
border-radius: 3px;
color: #fff;
margin-top: 1rem;
float: right;
cursor: pointer;
}
Here is the JS which works:
var input_textarea = document.querySelector(".content-input");
var output_div = document.querySelector(".content-output");
var save_button = document.querySelector(".save-button");
save_button.addEventListener("click", updateOutput);
output = localStorage.getItem("content");
input = localStorage.getItem("content");
console.log(output);
output_div.textContent = output;
function updateOutput() {
console.log("clicked button");
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
And here is the jquery which doesn't work:
var input_textarea = $(".content-input");
var output_div = $(".content-output");
var save_button = $(".save-button");
save_button.on("click", updateOutput);
output_div.textContent = localStorage.getItem("content");
input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
event.preventDefault();
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
I'm running out of ideas and searches - probably a typo but I cant find it . I've tried text() which was the advice 6 years ago. JSON.stringify and parse don't help because it's just a string.
I'm hoping someone has done some refactoring and spots the differences - I've even run this in the console but I can only add the text to localstorage manually: localstorage.setItem('content', 'help')
Thanks in advance
The problem is that you are trying to select a array, get the value of that array, and output to another array. I think jquery does that when you select a class, (because there could be more than one of them). Simple solution to this..
var input_textarea = $(".content-input")[0];
console.log(input_textarea)
var output_div = $(".content-output")[0];
var save_button = $(".save-button");
save_button.on("click", updateOutput);
output_div.textContent = localStorage.getItem("content");
input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
console.log('hello')
event.preventDefault();
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
Found it: val() to set and text() to get.
var input_textarea = $(".content-input");
var output_div = $(".content-output");
var save_button = $(".save-button");
save_button.on("click", updateOutput);
// input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
event.preventDefault();
localStorage.setItem("content", input_textarea.val());
output_div.text(localStorage.getItem("content"));
}
this post helped: How to save the value of textarea to localstorage then display it in the same textarea
im creating to-do list without any tutorial and i stucked when i tried to code clear button. I have a problem because this code removing only half of 'li' items in my list. I checked length of document.querySelectorAll('li) and it return correct value of list length , and i think in each loop execution i delete first element because document.querySelector('li) return only first element. Could you help me? And another question : Is somewhere in web program that can i see step by step exection of my code with DOM? I found few sites but there i can only debug code without html and css.
There is my code:
let clear = document.querySelector('.clear');
let input = document.querySelector('.input');
let submit = document.querySelector('.submit');
let list = document.querySelector('.list');
submit.addEventListener('click', function() {
const el = document.createElement('li');
list.appendChild(el);
let items = document.querySelectorAll('li');
for (i = 0; i < items.length; i++) {
items[items.length - 1].textContent = input.value;
}
});
clear.addEventListener('click', function() {
console.log(document.querySelectorAll('li').length);
for (i = 0; i < document.querySelectorAll('li').length; i++)
list.removeChild(document.querySelector('li'));
console.log(list);
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
max-height: 100vh;
max-width: 90vw;
}
h1 {
text-align: center;
}
.wrap {
padding: 50px;
border: 2px solid black;
border-radius: 20%;
background-color: red;
}
.list {
width: 100%;
margin-left: 100px;
font-size: 2rem;
font-weight: bold;
}
<!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>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrap">
<h1>To do list</h1>
<input type="text" placeholder="Add an item!" class="input" />
<button class="submit">Submit</button>
<button class="clear">Clear List</button>
</div>
<ol class="list"></ol>
<script src="script.js"></script>
</body>
</html>
In your case, your loop was calculating its length each time of the loop while i was still incrementing
I you had two elements, it would have deleted the first item, then at the second loop, the list would have a length of 1 and i would be equals to 1 so the loop would break
You can use a for of loop instead of a for i loop and remove the child by reference
clear.addEventListener('click', function() {
const childs = document.querySelectorAll('li')
for (const child of childs){
list.removeChild(child)
}
});
Note : this can also be done using a for i loop if you instantiate the list
clear.addEventListener('click', function() {
const childs = document.querySelectorAll('li')
for (let i = 0; i < childs.length; i++){
list.removeChild(childs[i])
}
});
I invent a new way to solve it
clear.addEventListener('click', function () {
for (i = 0; i < document.querySelectorAll('li').length + i; i++)
list.removeChild(document.querySelector('li'));
console.log(list);
});
In each iteration I add 'i' . So i update length
I created this color guessing game from scratch using HTML, CSS and JS. You're given a random RGB value and you guess which out of three given colors is the correct one. Now I want to take it a step higher by adding a scoreboard and score (Which I'm not sure how to do at all) and a full-screen congratulation message when you guess the color right. I've tried doing that but the animation doesn't seem to work.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<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>Document</title>
</head>
<body>
<h1 class="text-centered" id="main-h1">Guess The Color!</h1>
<h2 class="text-centered" id="colorguess"></h2>
<p id="score">
</p>
<div class="box-container">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
<div id="bravo">
<p id="bravo-text">
BRAVO
</p>
</div>
</body>
<script src="script.js"></script>
</html>
CSS
*{
box-sizing: border-box;
}
body{
font-family: arial;
background-color: #1c1874;
color: rgb(105, 105, 139);
color: #fff;
}
.text-centered{
text-align: center;
text-shadow: 0px 2px 2px rgba(150, 150, 150, 1);
}
.box-container{
padding: 200px;
align-self: center;
display: flex;
flex-direction: row;
justify-content:space-evenly;
}
.box{
width: 200px;
height: 200px;
border-radius: 20px;
cursor: pointer;
border:5px solid #ffffff;
}
#score{
font-weight: 500;
font-size: 2em;
position: fixed;
top: 5%;
left: 5%;
}
#score::before {
content: "Score: ";
}
#bravo{
position: fixed;
display: none;
opacity: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
text-align: center;
font-size: 5em;
background-color: rgba(4, 8, 97, 0.69);
}
#bravo-text{
flex: 0 0 120px;
text-shadow: 0px 2px 2px rgba(150, 150, 150, 1);
}
JS
function getrandomcolor(){
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
rgb = "rgb("+r+", "+g+", "+b+")";
return rgb;
}
function gamestart(){
var mainh1 = document.getElementById('main-h1');
mainh1.innerHTML = "Guess the color!";
rgbvaluetrue = getrandomcolor();
var rgb = document.getElementById('colorguess');
rgb.innerHTML = rgbvaluetrue;
var body = document.getElementsByTagName('body');
var box = document.getElementsByClassName('box');
var scoreboard= document.getElementById('score');
var score = 0;
function displaybravo(element){
var op= 0;
var timer = setInterval(function () {
if (op >= 1){
clearInterval(timer);
}
if(op>=0.1){
element.style.display = "flex";
element.style.flexDirection = "column";
element.style.justifyContent = "center";
element.style.alignItems="center";
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 10);
}
for(var i=0;i<box.length;i++){
box[i].style.backgroundColor = getrandomcolor();
}
//here I am trying to assign the initial rgb value to one of the divs randomly
var rand = Math.floor(Math.random() * box.length);
box[rand].style.backgroundColor = rgbvaluetrue;
//here I check if the div you clicked on is correct
function markSelection() {
if(this.style.backgroundColor == rgbvaluetrue) {
mainh1.innerHTML="BRAVO";
setTimeout(function() {
var brv = document.getElementById('bravo');
displaybravo(brv);
gamestart(); }, 2000);
} else {
gamestart();
}
}
for(var i=0;i<box.length;i++){
box[i].onclick = markSelection;
}
scoreboard.innerHTML=score;
}
gamestart();
I reviewed your game and made some changes to the code based on what stood out to me. There were a few bugs that were important to correct, and many things I changed purely for readability / preference.
I tend to avoid directly using timeouts. Promises are a good way to control the order of things in javascript. This game could likely benefit from OOP to make the logic more organized, but I didn't want to return you something that was completely unrecognizable. You are welcome to take this to code review for a more complete refactoring.
The first issue that I noticed is that your setInterval never resolves with the logic implemented. Because it never resolves, every time you attempted to show the bravo message, it would start an interval at 10 ms, and they would stack on top of eachother. This quickly would become an issue, potentially even breaking your page. Instead of attempting to redesign your interval logic, I decided to use the css transition attribute to handle the Bravo message, and I threw in a keyframe animation so you could see how to add other effects without javascript. Instead of having to write logic in js and preform resource expensive operations, I can leave the animation to css. Now js just needs to add and remove the hidden class.
I also wrote a helper function wait at the top of the js, and made functions with waiting async so I could use the await keyword instead of nesting my code inside timeouts. This is more readable in my own opinion.
To add a score, I moved the score variable above the gameStart function. This way each time the game restarts, the score is not affected. Then I just had to increment the score variable whenever a correct answer is given, and change the text in the dom.
One bug I noticed was that the correct answer could have been clicked several times, and the points would have increased, because the event listener was still active after the answer was submitted. To handle this, I changed the way the event listener was applied. Instead of using element.onclick =, I opted for el.addEventListener("click", . This allowed me to use .removeEventListener once the answer was given, and only reapply the event listener once the next round started. I also added a wait for incorrect answers, and some text when the wrong answer was given.
Other more cosmetic changes include using a helper function $ to make grabbing elements easier, and changing .innerHTML to .innerText to more clearly show intent / prevent potential bugs.
I didn't correct it in this code, but it's worth mentioning variable names in javascript are usually camel case. i.e. instead of getrandomcolor it would be getRandomColor
If you have any questions about my code, please ask đ
const wait = t => new Promise(r => setTimeout(r, t));
const $ = (str, dom = document) => [...dom.querySelectorAll(str)];
function getrandomcolor(){
const random255 = () => Math.floor(Math.random() * 256);
const [r, g, b] = Array.from({length: 3}, random255);
return "rgb(" + r + ", " + g + ", " + b + ")";
}
let scoreboard = $('#score')[0];
let score = 0;
function gamestart(){
var mainh1 = $('#main-h1')[0];
mainh1.innerText = "Guess the color!";
rgbvaluetrue = getrandomcolor();
var rgb = $('#colorguess')[0];
rgb.innerText = rgbvaluetrue;
var body = document.body;
var allBoxes = $('.box');
async function displaybravo(element){
element.classList.remove("hidden");
await wait(2000);
element.classList.add("hidden");
await wait(1000);
}
for (var i=0; i<allBoxes.length; i++) {
allBoxes[i].style.backgroundColor = getrandomcolor();
}
var randomBoxIndex = Math.floor(Math.random() * allBoxes.length);
allBoxes[randomBoxIndex].style.backgroundColor = rgbvaluetrue;
async function markSelection() {
allBoxes.forEach(box => box.removeEventListener("click", markSelection));
if (this.style.backgroundColor == rgbvaluetrue) {
score++;
scoreboard.innerText = score;
mainh1.innerText = "BRAVO";
var brv = $('#bravo')[0];
await displaybravo(brv);
gamestart();
} else {
mainh1.innerText = "NOPE!";
await wait(1000);
gamestart();
}
}
allBoxes.forEach(box => box.addEventListener("click", markSelection));
scoreboard.innerHTML = score;
}
gamestart();
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: arial;
background-color: #1c1874;
color: rgb(105, 105, 139);
color: #fff;
}
.text-centered{
text-align: center;
text-shadow: 0px 2px 2px rgba(150, 150, 150, 1);
}
.box-container{
padding: 200px;
align-self: center;
display: flex;
flex-direction: row;
justify-content:space-evenly;
}
.box{
width: 200px;
height: 200px;
border-radius: 20px;
cursor: pointer;
border:5px solid #ffffff;
}
#score{
font-weight: 500;
font-size: 2em;
position: fixed;
top: 5%;
left: 5%;
}
#score::before {
content: "Score: ";
}
#bravo {
overflow: hidden;
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100%; /*needed to transition to / from*/
transition: height 2s;
}
#bravo.hidden {
height: 0;
}
#bravo-text {
font-size: 5rem;
font-weight: bold;
color: black;
animation: glow 1s ease-in-out infinite alternate;
}
#keyframes glow {
from {
text-shadow:
0 0 5px #fff,
0 0 10px #fff,
0 0 15px #e60073,
0 0 20px #e60073,
0 0 25px #e60073,
0 0 30px #e60073,
0 0 35px #e60073;
}
to {
text-shadow:
0 0 10px #fff,
0 0 20px #ff4da6,
0 0 30px #ff4da6,
0 0 40px #ff4da6,
0 0 50px #ff4da6,
0 0 60px #ff4da6,
0 0 70px #ff4da6;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="main.css">
<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>Document</title>
<script defer src="main.js"></script>
</head>
<body>
<h1 class="text-centered" id="main-h1">Guess The Color!</h1>
<h2 class="text-centered" id="colorguess"></h2>
<p id="score">
</p>
<div class="box-container">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
<div id="bravo" class="hidden flexCenter">
<p id="bravo-text" class="flexCenter">
BRAVO
</p>
</div>
</body>
</html>
I have written this code to get the squares of a grid to change their background color to black upon a mouseover event. It works when the page initially loads, but if I create a new grid the mouseover event no longer works.
I updated the original post with a snippet. Sorry I didn't do that from the beginning.
let number = 16;
makeGrid(number);
function makeGrid(number) {
for (let i=0; i < number; i++) {
for (let j=0; j < number; j++) {
const rows = document.createElement('div');
const container = document.getElementById('container')
rows.setAttribute('class', 'rows');
container.appendChild(rows);
}
}
container.style.gridTemplateColumns = `repeat(${number}, 1fr)`;
container.style.gridTemplateRows = `repeat(${number}, 1fr)`;
}
//create new grid with on button
let newGrid = document.getElementById('newGrid');
newGrid.addEventListener('click', () => {
let number = prompt('Enter a number');
let container = document.getElementById('container');
container.textContent = '';
makeGrid(number);
})
//change background color to black
let changeClass = document.querySelectorAll('.rows');
changeClass.forEach((item) => {
item.addEventListener('mouseover', e => {
item.style.backgroundColor = 'black';
})
})
body {
background-color: rgb(5, 51, 5) ;
}
#container {
margin: auto;
width: 500px;
height: 500px;
display: grid;
border-style: solid;
border-width: thin;
border-color: lightslategray;
background-color: white;
}
.rows{
}
.black { background-color: black;
}
#header {
text-align: center;
}
#button {
text-align: center;
}
#footer {
text-align: center;
}
#newGrid {
background-color: lightgray;
color: darkcyan;
font-size: 20px;
padding: 12px 28px;
border-radius: 0px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Etch-a-Sketch</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1 id='header'>Etch-a-Sketch</h1>
<br>
<div id='button'>
<button id='newGrid' class='button'>New Grid</button>
</div>
<br>
<br>
<div id='container'></div>
<br>
<footer id='footer'>Made by: Joe Maniaci</footer>
<script src="main.js"></script>
</body>
</html>
When you query the DOM with document.querySelectorAll('.rows') and add the event listeners, there is only one "grid" in the DOM at that time. When a "grid" is subsequently added to the DOM, as triggered by the user's click event, you must instantiate event listeners on the newly added DOM nodes too.
A way to avoid this problem and a better approach overall in your situation is to use delegated event listeners. For example:
document.addEventListener('mouseover', e=>{
if(e.target.matches(â.myClickableItemClassâ){
e.target.style.backgroundColor = 'black';
}
}
Learn more about event delegation here: https://medium.com/#bretdoucette/part-4-what-is-event-delegation-in-javascript-f5c8c0de2983
I'm working on a bootcamp and some guys and I have created a group. We are trying to dynamically create html elements using pure JavaScript. The elements are there but we get an error running and we want to be able to go back and use/grab those elements later. Any advice on what we are doing wrong would be much appreciated.
The HTML:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JavaScript Grid</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="grid"></div>
<script src="js/script.js" type="text/javascript"></script>
</body>
</html>
The js:
(function() {
var grid = document.getElementById("grid");
for (var i = 0; i < 5; i++) {
var temp = document.createElement("DIV");
temp.className = "row";
grid.appendChild(temp);
}
var row = grid.getElementsByClassName("row");
})();
The CSS:
.grid {
height: 100%;
width: 100%;
overflow: auto;
background-color: black;
}
.row {
overflow: auto;
}
.box {
padding: 0;
box-sizing: border-box;
background-color: white;
height: 100px;
float: left;
}
Thanks!
I see no error on your code.
your divs are collected and you can play with them around. take a look to the jsfiddle and open your console. (press F12 or inspect element on right mouse click).
(function() {
var grid = document.getElementById("grid");
for (var i = 0; i < 5; i++) {
var temp = document.createElement("DIV");
temp.className = "row";
grid.appendChild(temp);
}
var row = grid.getElementsByClassName("row");
row[row.length - 1].style.borderColor = "blue";
row[0].style.borderColor = "red";
})();
and the css
.row {
background.color:#f2f2f2;
border: 1px solid #dadada;
margin-bottom:10px;
height:20px;
}
http://jsfiddle.net/hu7a7k0s/