I'm trying to build a very basic chess board (with no embedded rules) as a learning challenge. Basically my board is made of 64 divs, where each div has a class .square. I have two functions: one for adding the .active class to the clicked square, and another function for moving the piece with the .active class to the new square. I've tried to put the two different eventListeners to call the different functions in an IF ELSE statement, but my condition doesn't work because the querySelector doesn't check in real time if there's any div with the class .active at that given moment.
My code looks like this:
let squares = document.querySelectorAll(`.square`);
let activeSquares = document.querySelectorAll(`.active`);
// This condition needs to check if there's any square with the class .active in REAL TIME
if (activeSquares.length > 0) {
squares.forEach(square => {
square.addEventListener(`click`, movePiece);
function movePiece() {
let pieceToMove = document.querySelector(`.active`).textContent;
square.textContent = pieceToMove;
}
});
} else {
squares.forEach(square => {
square.addEventListener(`click`, selectPiece);
function selectPiece() {
square.className = `active square`;
}
});
}
How do I make it check for the class in real time? Or is my approach completely wrong?
Please be merciful, I've only been learning this stuff for a couple months, if I'm missing some basic knowledge please point it out so I can look it up.
Thanks!
In the event handler (a function that is called when a registered event is triggered) we use the Event Object property Event.target which always points to the tag that the user interacted with. Read the following articles for more details:
Events
Event Delegation
Details are commented in example
// Reference <table>
const board = document.querySelector('.board');
// This function goes beyond the scope of the question
const buildTable = table => {
const file = ['a', 'b', 'c', 'd', 'e', 'f', 'h', 'g'];
const rank = [8, 7, 6, 5, 4, 3, 2, 1];
let matrix = [];
for (let r = 0; r < 8; r++) {
let row = table.insertRow();
matrix.push([]);
for (let c = 0; c < 8; c++) {
let col = row.insertCell();
col.dataset.pos=`${file[c]+rank[r]}`;
matrix[r].push(`${file[c]+rank[r]}`);
}
}
return matrix;
};
const matrix = buildTable(board);
//console.log(matrix);
// Bind the 'click' event to <table>
board.onclick = activeSQ;
function activeSQ(e) {
// Reference the tag user clicked
const clk = e.target;
/*
If the user clicked a <td>...
...remove .active from the <td> that was .active previously...
...then add .active to the <td> the user clicked...
...log the algebraic notation of the clicked square
*/
if (clk.matches('td')) {
const prev = this.querySelector('td.active');
if (prev) {
prev.classList.remove('active');
}
clk.classList.add('active');
console.log(clk.dataset.pos);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
}
:root {
font: 1vw/1 'Segoe UI';
}
html,
body {
width: 100%;
height: 100%;
}
body {
overflow: hidden;
}
table {
table-layout: fixed;
border-collapse: collapse;
width: 40%;
margin: 2.5% auto;
border: 0.5px solid lightgrey;
}
td {
width: 12.5%;
height: 5rem;
border: 0.5px solid lightgrey;
}
tr:nth-of-type(odd) td:nth-of-type(even) {
background: black;
}
tr:nth-of-type(even) td:nth-of-type(odd) {
background: black;
}
.pos {
display: block;
}
.white,
.black {
display: inline-flex;
justify-content: center;
align-items: center;
width: 90%;
height: 90%;
}
td.active {
outline: 3px inset gold;
}
.as-console-row::after { width: 0; font-size: 0; }
.as-console-row-code { width: 100%; word-break: break-word; }
.as-console-wrapper { max-height: 25% !important; }
<table class='board'></table>
Its simple code will look like this, you can develop it :
const squares = document.getElementsByClassName('square')
Array.from(squares).forEach(ele => {
ele.addEventListener('click', function () {
if(this.classList.contains('active')) {
this.classList.remove("active")
} else {
currentActive = document.getElementsByClassName('active')[0]
if (currentActive) {
let thisHtml = this.innerHTML
this.innerHTML = currentActive.innerHTML
currentActive.innerHTML = thisHtml
currentActive.classList.remove("active")
} else {
this.classList.add("active")
}
}
})
})
#container {
height: 169px;
width: 169px;
}
.square {
height: 40px;
width: 40px;
background-color: #ccc;
float:left;
left: 0;
border: solid 1px;
}
.active {
background-color: red;
}
<div id="container">
<div class='square'>1</div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
<div class='square'></div>
</div>
Related
The expected result is that when you click on each panel, the panel you clicked on moves, then moves back when you click it again.
The result with my current code is that no matter which panel you click it is always panel4 that toggles.
The reason these need to be added dynamically to each is because this list of panels will be auto populated and have the target ids dynamically generated too.
The Code....
var plbelements = document.getElementsByClassName("panel");
for (var l = 0; l < plbelements.length; l++) {
targetPanel = document.getElementById(plbelements[l].id);
actionSwipeAmount = "160px";
console.log("Target Panel before event listener = " + targetPanel.id);
targetPanel.addEventListener("click", (e) => {
left = window.getComputedStyle(targetPanel).getPropertyValue("left");
console.log(targetPanel.id);
if (left != actionSwipeAmount) {
targetPanel.style.left = actionSwipeAmount;
} else {
targetPanel.style.left = "0px";
}
});
}
body {
margin: 0;
}
.panelsContainer {
display: block;
max-width: 360px;
width: 100%;
min-height: 50px;
border: 1px solid black;
box-sizing: border-box;
overflow: hidden;
position: relative;
}
.underPanel {
display: block;
width: 360px;
min-height: 50px;
border: 1px solid black;
background-color: #6c6c6c;
color: white;
padding: 5px;
box-sizing: border-box;
position: relative;
color: white;
}
.panel {
display: block;
width: 360px;
min-height: 50px;
border: 1px solid black;
background-color: #141414;
color: white;
padding: 5px;
box-sizing: border-box;
position: absolute;
right: 0px;
top: 0px;
}
.underPanel:nth-child(even) > .panel {
background-color: #303030;
}
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0">
<div class="panelsContainer">
<div class="underPanel">Hello
<div id="panel1" class="panel">1</div>
</div>
<div class="underPanel">Hello
<div id="panel2" class="panel">2</div>
</div>
<div class="underPanel">Hello
<div id="panel3" class="panel">3</div>
</div>
<div class="underPanel">Hello
<div id="panel4" class="panel">4</div>
</div>
</div>
For solving your problem, you need to redefine the target variable in for loop using const like this:
const targetPanel = document.getElementById(plbelements[l].id);
And you'd better use const and let instead of var. The entire JavaScript code is as follows:
const plbelements = document.getElementsByClassName("panel");
for (let l = 0; l < plbelements.length; l++) {
const targetPanel = document.getElementById(plbelements[l].id);
const actionSwipeAmount = "160px";
console.log("Target Panel before event listener = " + targetPanel.id);
targetPanel.addEventListener("click", (e) => {
left = window.getComputedStyle(targetPanel).getPropertyValue("left");
console.log(targetPanel.id);
if (left != actionSwipeAmount) {
targetPanel.style.left = actionSwipeAmount;
} else {
targetPanel.style.left = "0px";
}
});
}
This code adds a class (a border in this case) to an single element (a square) when the user clicks on that element. This part of the code is working fine.
I would then like to be able to remove however many borders were added (1-3 in this example), with the click of a single button, using a for loop.
I was able to do remove the borders by just repeating item1.classList.remove('.bigBorder'); (for example with item1) but that certainly does not scale well.
const item = document.querySelector('.item');
const item1 = document.querySelector('.item1');
const item2 = document.querySelector('.item2');
const item3 = document.querySelector('.item3');
const clearBordersButton = document.querySelector('.clearBorders');
const bigBorder = document.querySelector('.bigBorder');
item1.addEventListener('click', function() {
item1.classList.add('bigBorder');
});
item2.addEventListener('click', function() {
item2.classList.add('bigBorder');
});
item3.addEventListener('click', function() {
item3.classList.add('bigBorder');
});
clearBordersButton.addEventListener('click', clearBorders);
function clearBorders() {
for (let i = 0; i < item.length; i++) {
item[i].classList.remove('bigBorder');
}
};
* {
box-sizing: border-box;
}
.container {
width: 960px;
margin: 20px auto;
border: 1px solid black;
}
.boxes {
display: flex;
justify-content: space-around;
border: 1px solid black;
}
.item1,
.item2,
.item3 {
border: 2px solid blue;
margin: 20px 0;
width: 100px;
height: 100px;
}
.bigBorder {
border: 10px solid black;
}
<div class="container">
<div class="boxes">
<div class="item item1">item</div>
<div class="item item2">item</div>
<div class="item item3">item</div>
</div>
<button class="clearBorders">clear borders</button>
</div>
Instead of attaching a listener to each item you can use event delegation - attach one listener to the parent component (.boxes) and have that listen to events as they "bubble up" the DOM from its children.
If you also select all the item elements with querySelectorAll it's a simple process to iterate over them and remove the class.
// Cache the elements
const boxes = document.querySelector('.boxes');
const items = document.querySelectorAll('.item');
const clear = document.querySelector('.clear');
// Add listeners to the container, and the button
boxes.addEventListener('click', handleClick, false);
clear.addEventListener('click', clearBorders, false);
// Because we're using event delegation
// check that the child element that was clicked
// on was has a `.item` class, and then add the new class
function handleClick(e) {
if (e.target.matches('.item')) {
e.target.classList.add('bigBorder');
}
}
function clearBorders() {
items.forEach(item => {
item.classList.remove('bigBorder');
});
};
.boxes{display:flex;justify-content:space-around;width:250px}
.item{display:flex;justify-content:center;align-items:center;background-color:#efefef;border:10px solid white;margin:20px 0;width:50px;height:50px}
.item:hover{cursor:pointer;background-color:#cdcdcd;}
.bigBorder{border:10px solid #000}
<div class="boxes">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<button class="clear">clear borders</button>
It's important to note that querySelector returns the first matching element where as querySelectorAll returns a node list of matching elements.
We can use the node list to assign the event lister and remove the class.
//Selects multimple itmes
const items = document.querySelectorAll('.item');
//selects first matching itme
const clearBordersButton = document.querySelector('.clearBorders');
const bigBorder = document.querySelector('.bigBorder');
//Iterate the items
items.forEach(function(element){
//add an event listern
element.addEventListener("click", function(){
//"this" is the item clicked
this.classList.add("bigBorder");
})
})
clearBordersButton.addEventListener('click', clearBorders);
function clearBorders() {
//find the elements
document.querySelectorAll(".item.bigBorder").forEach(function(element){
//remove the class
element.classList.remove("bigBorder");
})
};
* {
box-sizing: border-box;
}
.container {
width: 960px;
margin: 20px auto;
border: 1px solid black;
}
.boxes {
display: flex;
justify-content: space-around;
border: 1px solid black;
}
.item1,
.item2,
.item3 {
border: 2px solid blue;
margin: 20px 0;
width: 100px;
height: 100px;
}
.bigBorder {
border: 10px solid black;
}
<div>
<div class="container">
<div class="boxes">
<div class="item item1">item</div>
<div class="item item2">item</div>
<div class="item item3">item</div>
</div>
<button class="clearBorders">clear borders</button>
</div>
</div>
I have 10 links and each of them is different from the others.I want when user hovers on them background image of the div changes and a tooltip text be shown on top of the links with a fade-in animation .
i have tried to make several functions using JS and it works but it's a lot of code and mostly repetitive.I want a good shortcut through all of that useless coding.
document.getElementById("d1").onmouseover = function() {
mouseOver1()
};
document.getElementById("d2").onmouseover = function() {
mouseOver2()
};
document.getElementById("d3").onmouseover = function() {
mouseOver3()
};
document.getElementById("d1").onmouseout = function() {
mouseOut1()
};
document.getElementById("d2").onmouseout = function() {
mouseOut2()
};
document.getElementById("d3").onmouseout = function() {
mouseOut3()
};
function mouseOver1() {
document.getElementById("dogs").style.background = "blue";
document.getElementById("tooltiptext1").style.visibility = "visible";
}
function mouseOut1() {
document.getElementById("dogs").style.background = "black";
document.getElementById("tooltiptext1").style.visibility = "hidden";
}
function mouseOver2() {
document.getElementById("dogs").style.background = "green";
document.getElementById("tooltiptext2").style.visibility = "visible";
}
function mouseOut2() {
document.getElementById("dogs").style.background = "black";
document.getElementById("tooltiptext2").style.visibility = "hidden";
}
function mouseOver3() {
document.getElementById("dogs").style.background = "red";
document.getElementById("tooltiptext3").style.visibility = "visible";
}
function mouseOut3() {
document.getElementById("dogs").style.background = "black";
document.getElementById("tooltiptext3").style.visibility = "hidden";
}
#dogs {
float: right;
margin-top: 5%;
background: black;
width: 150px;
height: 150px;
}
#d-list {
color: white;
direction: ltr;
float: right;
width: 60%;
height: 60%;
}
#tooltiptext1,
#tooltiptext2,
#tooltiptext3 {
color: black;
background-color: gray;
width: 120px;
height: 30px;
border-radius: 6px;
text-align: center;
padding-top: 5px;
visibility: hidden;
}
<div id="animals">
<div id="dogs"></div>
<div id="d-list">
<pre style="font-size:22px; color:darkorange">dogs</pre><br />
<pre>white Husky</pre>
<p id="tooltiptext1">Tooltip text1</p>
<pre>black Bull</pre>
<p id="tooltiptext2">Tooltip text2</p>
<pre>brown Rex</pre>
<p id="tooltiptext3">Tooltip text3</p>
</div>
</div>
Please have in mind that all of links will change same outer div object and the idea is to change the background image of that div and the tooltip shoud appear on the top of the links....so,
any ideas?
edit: added animation requested.
CSS is almost always better done in script by using classes when multiple elements are being manipulated with similar functions so I used that here. Rather than put some complex set of logic in place I simply added data attributes for the colors - now it works for any new elements you wish to add as well.
I did find your markup to be somewhat strangely chosen and would have done it differently but that was not part of the question as stated.
I took the liberty of removing the style attribute from your dogs element and put it in the CSS also as it seemed to belong there and mixing markup and css will probably make it harder to maintain over time and puts all the style in one place.
Since you DID tag this with jQuery here is an example of that.
$(function() {
$('#d-list').on('mouseenter', 'a', function(event) {
$('#dogs').css('backgroundColor', $(this).data('colorin'));
$(this).parent().next('.tooltip').animate({
opacity: 1
});
}).on('mouseleave', 'a', function(event) {
$('#dogs').css('backgroundColor', $(this).data('colorout'));
$(this).parent().next('.tooltip').animate({
opacity: 0
});
});
});
#dogs {
float: right;
margin-top: 5%;
background: black;
width: 150px;
height: 150px;
}
#d-list {
color: white;
direction: ltr;
float: right;
width: 60%;
height: 60%;
}
.dog-header {
font-size: 22px;
color: darkorange;
margin-bottom: 2em;
}
.tooltip {
color: black;
background-color: gray;
width: 120px;
height: 30px;
border-radius: 6px;
text-align: center;
padding-top: 5px;
opacity: 0;
position:relative;
top:-4.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div id="animals">
<div id="dogs"></div>
<div id="d-list">
<pre class="dog-header">dogs</pre>
<pre>white Husky</pre>
<p id="tooltiptext1" class="tooltip">Tooltip text1</p>
<pre>black Bull</pre>
<p id="tooltiptext2" class="tooltip">Tooltip text2</p>
<pre>brown Rex</pre>
<p id="tooltiptext3" class="tooltip">Tooltip text3</p>
</div>
</div>
Updated
This answer was written before the question was edited to show the intended markup/styling and before all the details were included. The code has been updated to work with that structure.
I think the simplest thing is just to create a configuration object to detail the varying bits, and then use common code for the rest. Here's one approach:
const configs = [
['d1', 'tooltiptext1', 'blue'],
['d2', 'tooltiptext2', 'green'],
['d3', 'tooltiptext3', 'red'],
];
configs.forEach(([id, tt, color]) => {
const dogs = document.getElementById('dogs');
const el = document.getElementById(id);
const tip = document.getElementById(tt);
el.onmouseover = (evt) => {
dogs.style.background = color
tip.style.visibility = "visible";
}
el.onmouseout = (evt) => {
dogs.style.background = "black";
tip.style.visibility = "hidden";
}
})
#dogs{float:right;margin-top:5%;background:#000;width:150px;height:150px}#d-list{color:#fff;direction:ltr;float:right;width:60%;height:60%}#tooltiptext1,#tooltiptext2,#tooltiptext3{color:#000;background-color:gray;width:120px;height:30px;border-radius:6px;text-align:center;padding-top:5px;visibility:hidden}
<div id="animals"> <div id="dogs"></div><div id="d-list"> <pre style="font-size:22px; color:darkorange">dogs</pre><br/> <pre>white Husky</pre> <p id="tooltiptext1">Tooltip text1</p><pre>black Bull</pre> <p id="tooltiptext2">Tooltip text2</p><pre>brown Rex</pre> <p id="tooltiptext3">Tooltip text3</p></div></div>
Obviously you can extend this with new rows really easily. And if you want to add more varying properties, you can simply make the rows longer. If you need to add too many properties to each list, an array might become hard to read, and it might become better to switch to {id: 'demo', tt: 'dem', color: 'blue'} with the corresponding change to the parameters in the forEach callback. (That is, replacing configs.forEach(([id, tt, color]) => { with configs.forEach(({id, tt, color}) => {.) But with only three parameters, a short array seems cleaner.
Older code snippet based on my made-up markup.
const configs = [
['demo', 'dem', 'blue'],
['dd', 'dem1', 'green']
];
configs.forEach(([id1, id2, color]) => {
const a = document.getElementById(id1)
const b = document.getElementById(id2)
a.onmouseover = (evt) => {
a.style.background = color
b.style.visibility = "visible";
}
a.onmouseout = (evt) => {
a.style.background = "black";
b.style.visibility = "hidden";
}
})
div {width: 50px; height: 50px; float: left; margin: 10px; background: black; border: 1px solid #666; color: red; padding: 10px; text-align: center}
#dem , #dem1{visibility:hidden;}
<div id="demo">demo</div>
<div id="dem">dem</div>
<div id="dd">dd</div>
<div id="dem1">dem1</div>
my way of seeing that => zero Javascript:
div[data-info] {
display: inline-block;
margin:80px 20px 0 0;
border:1px solid red;
padding: 10px 20px;
position: relative;
}
div[data-bg=blue]:hover {
background-color: blue;
color: red;
}
div[data-bg=green]:hover {
background-color: green;
color: red;
}
div[data-info]:hover:after {
background: #333;
background: rgba(0, 0, 0, .8);
border-radius: 5px;
bottom: 46px;
color: #fff;
content: attr(data-info);
left: 20%;
padding: 5px 15px;
position: absolute;
z-index: 98;
min-width: 120px;
max-width: 220px;
}
div[data-info]:hover:before {
border: solid;
border-color: #333 transparent;
border-width: 6px 6px 0px 6px;
bottom: 40px;
content: "";
left: 50%;
position: absolute;
z-index: 99;
}
<div data-info="Tooltip for A Tooltip for A" data-bg="blue">with Tooltip CSS3 A</div>
<div data-info="Tooltip for B" data-bg="green" >with Tooltip CSS3 B</div>
Hi guys I’m a beginner in JS could somebody help me please
I have created an HTML page with 3 country’s flags. When the user moves the mouse over one of the flags, display the name of the country in the text box. When they move the mouse away from the flag, clear the text box.
The problem is when I move the mouse on the flag many times the text repeated
Also how to refactor my code it is so repeated I know I must use foreach but how? here is my code
const photo = Array.from(document.querySelectorAll('.flag-img'));
const oman = document.querySelector('.oman');
const algeria = document.querySelector('.algeria');
const uae = document.querySelector('.uae');
const div1 = document.createElement("div1");
const div2 = document.createElement("div2");
const div3 = document.createElement("div3");
function countryName() {
const text1 = document.createTextNode("Oman");
div1.appendChild(text1);
div1.className = "box";
oman.appendChild(div1);
}
function countryAlg() {
const text2 = document.createTextNode("Algeria");
div2.appendChild(text2);
div2.className = "box";
algeria.appendChild(div2);
}
function countryUae() {
const text3 = document.createTextNode("UAE");
div3.appendChild(text3);
div3.className = "box";
uae.appendChild(div3);
}
function fadeOut() {
div1.parentNode.removeChild(div1);
}
function fadeOut2() {
div2.parentNode.removeChild(div2);
}
function fadeOut3() {
div3.parentNode.removeChild(div3);
}
oman.addEventListener('mouseenter', countryName);
algeria.addEventListener('mouseenter', countryAlg);
uae.addEventListener('mouseenter', countryUae);
oman.addEventListener('mouseleave', fadeOut);
algeria.addEventListener('mouseleave', fadeOut2);
uae.addEventListener('mouseleave', fadeOut3);
* {
margin: 0;
box-sizing: border-box;
}
header {
text-align: center;
}
#flag {
margin-top: 50px;
display: flex;
justify-content: space-around;
}
.flag-img img {
width: 200px;
}
.box {
text-align: center;
padding: 20px;
border: 2px solid black;
width: 100px;
height: 100px;
background-color: transparent;
color: black;
/*position: absolute;
left: 50px;
top: 50px;*/
}
<header>
<h1>Countries Flags</h1>
</header>
<div id="flag">
<div class="flag-img oman">
<img src="https://motionarray.imgix.net/preview-339277phSMy7aPd_0007.jpg?w=750&q=60&fit=max&auto=format">
</div>
<div class="flag-img algeria">
<img src="https://img.freepik.com/free-photo/flag-of-algeria_1401-52.jpg?size=338&ext=jpg">
</div>
<div class="flag-img uae">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_United_Arab_Emirates.svg/255px-Flag_of_the_United_Arab_Emirates.svg.png">
</div>
</div>
I tried to refractor this in your way :
Select all your elements
var flags = document.getElementsByClassName("flag-img");
Init elements with function.
for (var i = 0; i < flags.length; i++) {
(function () {
console.log(flags[i]);
var elem = flags[i];
flags[i].addEventListener('mouseenter', function() {
showCountry(elem)
}, false);
flags[i].addEventListener('mouseleave', function() {
fadeOut(elem)
}, false);
}());
}
Single function fadeout
function fadeOut(a) {
a.removeChild(a.lastChild);
}
Single function show.
function showCountry(a) {
const text = document.createTextNode(a.className.split(" ")[1]);
var div = document.createElement("div");
div.appendChild(text);
div.className = "box";
a.appendChild(div);
}
console.clear();
var flags = document.getElementsByClassName("flag-img");
for (var i = 0; i < flags.length; i++) {
(function () {
var elem = flags[i];
flags[i].addEventListener('mouseenter', function() {
showCountry(elem)
}, false);
flags[i].addEventListener('mouseleave', function() {
fadeOut(elem)
}, false);
}());
}
function fadeOut(a) {
a.removeChild(a.lastChild);
}
function showCountry(a) {
const text = document.createTextNode(a.className.split(" ")[1]);
var div = document.createElement("div");
div.appendChild(text);
div.className = "box";
a.appendChild(div);
}
* {
margin: 0;
box-sizing: border-box;
}
header {
text-align: center;
}
#flag {
margin-top: 50px;
display: flex;
justify-content: space-around;
}
.flag-img img {
width: 200px;
}
.box {
text-align: center;
padding: 20px;
border: 2px solid black;
width: 100px;
height: 100px;
background-color: transparent;
color: black;
/*position: absolute;
left: 50px;
top: 50px;*/
}
<header>
<h1>Countries Flags</h1>
</header>
<div id="flag">
<div class="flag-img oman">
<img src="https://motionarray.imgix.net/preview-339277phSMy7aPd_0007.jpg?w=750&q=60&fit=max&auto=format">
</div>
<div class="flag-img algeria">
<img src="https://img.freepik.com/free-photo/flag-of-algeria_1401-52.jpg?size=338&ext=jpg">
</div>
<div class="flag-img uae">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_United_Arab_Emirates.svg/255px-Flag_of_the_United_Arab_Emirates.svg.png">
</div>
</div>
instead of for loop I used forEach because i hate for loops
and the code worked
var flags = Array.from(document.getElementsByClassName("flag-img"));
flags.forEach(function(value) {
value.addEventListener('mouseenter', function() {
showCountry(value)
}, false);
value.addEventListener('mouseleave', function() {
fadeOut(value)
}, false);
});
function fadeOut(a) {
a.removeChild(a.lastChild);
}
function showCountry(a) {
const text = document.createTextNode(a.className.split(" ")[1]);
var div = document.createElement("div");
div.appendChild(text);
div.className = "box";
a.appendChild(div);
}
I know you're trying to learn Javascript, but this is far easier (and better performance-wise) to achieve using CSS only:
#flag {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
}
#flag img {
max-width: 100%;
}
.flag-img::after {
display: block;
content: attr(data-country);
opacity: 0;
text-align: center;
transition: opacity .4s ease-in-out;
}
.flag-img:hover::after {
opacity: 1;
}
<div id="flag">
<div class="flag-img" data-country="Oman">
<img src="https://motionarray.imgix.net/preview-339277phSMy7aPd_0007.jpg?w=750&q=60&fit=max&auto=format">
</div>
<div class="flag-img" data-country="Algeria">
<img src="https://img.freepik.com/free-photo/flag-of-algeria_1401-52.jpg?size=338&ext=jpg">
</div>
<div class="flag-img" data-country="United Arab Emirate">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cb/Flag_of_the_United_Arab_Emirates.svg/255px-Flag_of_the_United_Arab_Emirates.svg.png">
</div>
</div>
I am attempting to make a simon game. I'm trying to use the glowInOrder() function to make the divs glow in the order of the array. Unfortunately only the first div in the array glows, not the others that follow. (When I say 'glow', I simply mean add effect that looks like glow using CSS.) I suspect the issue is in the glowInOrder() function, but i am unable to find the issue.
Here's my code (also on CodePen):
var colorArray = ["red", "blue", "green", "yellow", "pink"];
var player = [];
var computer = [];
var round = 0;
var randomOrder;
var myColor;
var chosenColor;
//--------------------------------------------------------//
function makeGlow(yolo) {
$(yolo).addClass('hover');
setTimeout(function() {
$(yolo).removeClass('hover');
}, 300);
}
//--------------------------------------------------------//
function makeGlowTwo(yolo) {
setTimeout(function() {
$(yolo).addClass('hover');
}, 500);
setTimeout(function() {
$(yolo).removeClass('hover');
}, 800);
}
//--------------------------------------------------------//
function newGame() {
player = [];
computer = [];
round = 0;
}
//---------------------------------------------------------//
function playerChoice() {
$('.all').on('click', function(e) {
player.push(e.target.id);
makeGlow(this);
});
};
//---------------------------------------------------------//
function computerChoice() {
randomOrder = Math.floor(Math.random() * colorArray.length);
myColor = colorArray[randomOrder];
computer.push(myColor);
chosenColor = "#" + myColor;
makeGlowTwo(chosenColor);
}
//--------------------------------------------------------//
function newRound() {
round++;
glowInOrder();
}
//---------------------------------------------------------//
function glowInOrder() {
//computerChoice();//this may not work take out if you find it doesn't
var i = 1;
var moves = setInterval(function() {
makeGlowTwo(computer[i]);
i++;
if (i >= computer.length) {
clearInterval(moves);
}
}, 400)
}
//---------------------------------------------------------//
function arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length)
return false;
for (var i = arr1.length; i--;) {
if (arr1[i] !== arr2[i])
return false;
}
return true;
}
//---------------------------------------------------------//
$(document).ready(function() {
newGame();
playerChoice();
computerChoice();
$('.all').on('click', function() {
if (arraysEqual(computer, player)) {
alert('yes');
glowInOrder();
}
});
});
* {
margin: 0;
padding: 0;
}
body {
background-color: black;
}
.all {
border-radius: 50%;
height: 100px;
width: 100px;
}
#red {
border: 5px solid red;
display: table;
margin-left: auto;
margin-right: auto;
}
#blue {
border: 5px solid blue;
border-radius: 50%;
float: right;
display: inline;
}
#green {
border: 5px solid green;
border-radius: 50%;
display: inline-block;
}
#yellow {
border: 5px solid yellow;
border-radius: 50%;
display: inline-block;
margin-left: 40px;
}
#pink {
border: 5px solid pink;
border-radius: 50%;
float: right;
display: inline;
margin-right: 40px;
}
.middleRow {
margin-top: 70px;
margin-bottom: 110px;
}
.gameContainer {
height: 500px;
width: 500px;
margin-left: 25%;
margin-top: 10%;
}
.hover {
background-color: white;
}
<div class="container">
<div class="gameContainer">
<div class="topRow">
<div id="red" class="all"></div>
</div>
<div class="middleRow">
<div id="green" class="all"></div>
<div id="blue" class="all"></div>
</div>
<div class="bottomRow">
<div id="yellow" class="all"></div>
<div id="pink" class="all"></div>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Two issues that jump out:
You're only calling computerChoice once, and it adds only one entry to the array. So you have only one entry in computer at index 0.
Your glowInOrder function starts with i set to 1, which doesn't match any entry in your array. And naturally stops when you do the i >= computer.length check.
You need to ensure that computer has the correct number of entries (I'm guessing 5), and you need to start with i = 0 to start with the first one in your glowInOrder.
There are probably other logic issues in the code, but that's what's going on in relation to what you asked about. If you work through it in a debugger (there's one built into your browser) you'll be able to sort the other issues out.