How to add a transition to the carousel? - javascript

I have a carousel created on my own and I want to know how I can do that with JS. I know how I can do it by CSS but the problem is the change of the photos. Why change the src so that is my problem. If anyone knows how can I do it in JS it will be alright. Maybe changing the classes or something.
let imagenEnsaladas = document.getElementById("photosEnsaladas");
let buttonNext = document.getElementById("nextPhoto");
let carruselLi = document.getElementById("carruselLista").getElementsByTagName("li");
let positionCarrusel = 0;
let carruselPhotos = [
"assets/carrusel/ens.-ventresca-300-x300-300x300.png",
"assets/carrusel/ensalada bacalao200x200.png",
"assets/carrusel/ensalada-alcachofas-300x-300-300x300.jpg",
"assets/carrusel/ENsalada-yemas-300x300.png",
"assets/carrusel/ensalada-de-queso-cabra300x300-300x300.png",
];
window.onload = function playFoto() {
carruselLi[positionCarrusel].style.backgroundColor = "red";
if (positionCarrusel >= carruselPhotos.length) {
positionCarrusel++;
} else if (positionCarrusel > carruselPhotos.length) {}
imagenEnsaladas.src = carruselPhotos[positionCarrusel];
buttonNext.addEventListener("click", clickNextFoto);
function clickNextFoto() {
if (positionCarrusel >= carruselPhotos.length - 1) {
positionCarrusel = 0;
} else {
positionCarrusel++;
console.log(positionCarrusel);
}
imagenEnsaladas.src = carruselPhotos[positionCarrusel];
for (let i = 0; i < carruselLi.length; i++) {
if (i === positionCarrusel) {
carruselLi[positionCarrusel].style.backgroundColor = "red";
} else {
carruselLi[i].style.backgroundColor = "#1a1d20";
}
}
}
};
.textoNovedades {
margin: 0% 5% 0% 5%;
line-height: 30px;
}
.tablaNovedadesEnsalada {
display: flex;
flex-direction: row-reverse;
background: #1a1d20;
color: rgb(246, 225, 185);
justify-content: center;
align-items: center;
padding: 2% 2% 2% 2%;
width: 100%;
}
.carruselEnsaladas {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.nextPhoto {
background-image: url(assets/carrusel/siguiente.jpg);
background-size: auto;
background-position-x: 54%;
border-radius: 12px;
background-position-y: 47%;
width: 60%;
height: 9vh;
margin: 7%;
border: 3px;
box-shadow: 3px 3px 3px #999;
}
.tablaNovedadesEnsalada ul {
list-style: none;
}
<section class="tablaNovedadesEnsalada">
<div class="carruselEnsaladas">
<img src="" alt="photos carrusel" id="photosEnsaladas" class="photosEnsaladas">
<button id="nextPhoto" class="nextPhoto">
</button>
</div>
<p class="textoNovedades">
<ul id="carruselLista">
<li value="0"> ensalada de laminas de bacalao</li>
<li value="1"> Ensalada de alcachofas</li>
<li value="2"> Ensalada de yemas</li>
<li value="3">ensalada de ventresca</li>
<li value="4">Ensalada queso cabra</li>
</ul>
</p>
</section>

Related

Vanilla JS budget app delete dynamically rendered income or expense

I've made a budgeting app that has expenses and Income tabs. Every time you add an expense or income, the app pushes the information inside of an array of objects and dynamically renders an <li> component and places it inside of a <ul>. I'm having trouble with the edit and delete features. Each individual <li> comes with a delete and edit button. The <li>, delete button, and edit button all have the same id of Date.now(). Date.now() is used because it produces a number based on milliseconds and won't produce the same id twice unless someone types an expense or income twice within one millisecond I want to click on the delete button inside of the <li> and have my app remove that individual object from my entry_list[] array and also remove the <li> from the DOM.
'use strict'
const balanceElement = document.querySelector(".balance .value");
const totalIncome = document.querySelector(".income-total");
const totalOutcome = document.querySelector(".outcome-total");
const incomeElement = document.querySelector(".income-tab");
const expense = document.querySelector(".expense-tab");
const all = document.querySelector(".all-tab");
const incomeList = document.querySelector(".income-tab .list");
const expenseList = document.querySelector(".expense-tab .list");
const allList = document.querySelector(".all-tab .list");
const expensesButton = document.querySelector(".tab1");
const incomeButton = document.querySelector(".tab2");
const allButton = document.querySelector(".tab3");
const addExpense = document.querySelector(".add-expense")
const expenseTitle = document.querySelector(".expense-title-input")
const expenseAmount = document.querySelector(".expense-amount-input")
const addIncome = document.querySelector(".add-income")
const incomeTitle = document.querySelector(".income-title-input")
const incomeAmount = document.querySelector(".income-amount-input")
const list = document.querySelector('.list')
//SWITCHING BETWEEN TABS
expensesButton.addEventListener('click', () => {
expense.classList.remove('hidden');
incomeElement.classList.add('hidden');
expensesButton.classList.add('clicked');
incomeButton.classList.remove('clicked');
})
incomeButton.addEventListener('click', () => {
incomeElement.classList.remove('hidden');
expense.classList.add('hidden');
expensesButton.classList.remove('clicked');
incomeButton.classList.add('clicked');
})
incomeList.addEventListener('click', deleteOrEdit)
expenseList.addEventListener('click', deleteOrEdit)
let entry_list = []
addExpense.addEventListener('click', () =>{
if(expenseTitle.value == '' || expenseAmount.value == ''){
return;
}
let expense = {
type: 'expense',
title: expenseTitle.value,
amount: expenseAmount.value,
id: Date.now()
}
entry_list.push(expense)
clearExpense()
changeLists()
})
addIncome.addEventListener('click', () =>{
if(incomeTitle.value == '' || incomeAmount.value == ''){
return;
}
let income = {
type: 'income',
title: incomeTitle.value,
amount: incomeAmount.value,
id: Date.now()
}
entry_list.push(income)
clearIncome()
changeLists()
})
const clearExpense = () =>{
expenseTitle.value = '';
expenseAmount.value = '';
}
const clearIncome = () =>{
incomeTitle.value = ''
incomeAmount.value = ''
}
const changeLists = () =>{
expenseList.innerHTML = ''
incomeList.innerHTML = ''
entry_list.map((entry) =>{
if(entry.type == 'expense'){
return expenseList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
}
else if(entry.type == 'income'){
return incomeList.innerHTML += `<li id = "${entry.id}" class= "${entry.type}">
<div class = "entry">${entry.title}: $${entry.amount}</div>
<div class="icon-container">
<div class = "edit" id="${entry.id}"></div>
<div class ="delete" id="${entry.id}"></div>
</div>
</li>`
}
})
addIncomes()
}
const addIncomes = () =>{
let sum = 0;
let income = 0;
let outcome = 0;
balanceElement.innerHTML = 0
totalIncome.innerHTML = 0
totalOutcome.innerHTML = 0
entry_list.forEach(list =>{
if(list.type == 'expense'){
sum -= list.amount
outcome -= list.amount
}else if(list.type == 'income'){
sum += Number(list.amount)
income += Number(list.amount)
}
balanceElement.innerHTML = '$' + sum
totalIncome.innerHTML = '$' + income
totalOutcome.innerHTML = '$' + outcome
})
}
// // DETERMINE IF BUTTON IS EDIT OR DELETE
function deleteOrEdit(e){
const targetButton = e.target;
const entry = targetButton.parentNode.parentNode;
if(targetButton.classList == ('delete')){
deleteEntry(entry)
}else if(targetButton.classList == ('edit')){
editEntry(entry);
}
}
// //DELETE FUNCTION
const deleteEntry = (entry) =>{
console.log(entry.id)
entry_list.splice(entry.id, 1)
// entry.innerHTML = ''
console.log(entry.id)
addIncomes()
}
// EDIT FUNCTION
const editEntry = (entry) =>{
let Entry = entry_list[entry.id]
if(entry.type == "income"){
incomeAmount.value = Entry.amount;
incomeTitle.value = Entry.title;
}else if(entry.type == "expense"){
expenseAmount.value = Entry.amount;
expenseTitle.value = Entry.title;
}
deleteEntry(entry);
}
#import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght#400;700&family=Raleway:wght#400;700&display=swap');
*{
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Open Sans', sans-serif;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.budget-container{
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100%;
background-color: #4F98CA;
}
.balance-container{
width: 360px;
height: 470px;
background-color: #50D890;
border-radius: 30px;
margin-right: 100px;
}
.app-title{
color: white;
margin-top: 1rem;
margin-left: 1rem;
}
.month{
color: white;
margin-top: 1rem;
text-align: center;
}
.budget-header{
display: flex;
flex-direction:column;
justify-content: center;
}
.balance{
margin-top: 1rem;
margin-left: 1rem;
}
.title{
color: white;
font-size: 1.25rem;
opacity: .75;
}
.value{
font-size: 1.75rem;
color: white;
font-weight: bold;
margin-left: 1rem;
}
.account{
margin-top: 2.5rem;
margin: 2.5rem 1.5rem 2.5rem 1.5rem;
display: flex;
justify-content: space-between
}
.income-total{
color: white;
text-align: center;
font-size: 1.5rem;
}
.outcome-total{
color: #4F98CA;
text-align: center;
font-size: 1.5rem;
}
/* DASHBOARD */
.budget-dashboard{
display: block;
width: 360px;
height: 470px;
position: relative;
border-radius: 30px;
background-color: white;
}
.dash-title{
margin-top: 2rem;
margin-left: 1rem;
font-size: 1.5rem;
}
.toggle{
margin: 1rem;
display: flex;
cursor: pointer;
}
.toggle .tab2, .tab3{
margin-left: 1rem;
cursor: pointer;
}
.clicked{
font-weight: bold !important;
}
.hidden{
display: none !important;
}
/* EXPENSES TAB */
.expense-tab{
display: flex;
justify-content: center;
}
.expense-input-container{
position: absolute;
top: 400px;
border-top: solid 1px gray;
width: 100%;
}
.expense-amount-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.expense-title-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.add-expense{
color: none;
background-color: none;
border: none;
outline: none;
color: inherit;
}
/* INCOME TAB */
.income-tab{
display: flex;
justify-content: center;
}
.income-input-container{
position: absolute;
top: 400px;
border-top: solid 1px gray;
width: 100%;
}
.input{
display: flex;
justify-content: space-between;
align-items: center;
margin: 1rem;
}
.income-amount-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.income-title-input{
width: 125px;
border: none;
outline: none;
font-size: 1.25rem;
}
.add-income{
color: none;
background-color: none;
border: none;
outline: none;
}
.plus-img{
width: 40px;
}
/* li */
ul{
width: 360px;
height: 255px;
list-style: none;
margin-top:20px;
overflow-x: auto;
}
/* BUTTON ICONS */
.edit{
background-image: url('media/Icons/icons8-edit-48.png');
background-size: contain;
width: 25px;
height: 25px;
background-repeat: no-repeat;
margin-right: 10px;
}
.delete{
background-image: url('media/Icons/icons8-trash-can-48 (2).png');
background-size: contain;
width:25px;
height: 25px;
background-repeat: no-repeat;
}
.income{
width:250px;
height: auto;
padding-left: 20px;
margin-bottom: 10px;;
word-wrap: break-word;
color: black
}
.expense{
width:250px;
height: auto;
padding-left: 20px;
margin-bottom: 10px;;
word-wrap: break-word;
font-family: 'Gilroy Bold';
color: #4F98CA;
}
li{
display: flex;
justify-content: space-between;
width: 100% !important;
padding-right: 20px;
}
.icon-container{
display: flex;
}
#media (max-width:900px){
.budget-container{
display: inline-block;
position: relative
}
.balance-container{
position: absolute;
top: 10%;
left: 25%;
}
.budget-dashboard{
position: absolute;
left: 25%;
top: 40%;
}
}
<!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>Budgetrr</title>
</head>
<body>
<main class="budget-container">
<section class="balance-container">
<div class="app-title">
<p>Budgetrr</p>
</div>
<h1 class="month">OCTOBER</h1>
<section class="budget-header">
<div class="balance">
<div class="title">
Balance
</div>
<div class="value">
<small>$</small>0
</div>
</div>
<div class="account">
<div class="budget-income">
<div class="title">
Income
</div>
<div class="income-total">
<small>$</small>0
</div>
</div>
<div class="chart"></div>
<div class="budgetoutcome">
<div class="title">
Expenses
</div>
<div class="outcome-total">
<small>$</small>0
</div>
</div>
</div>
</section>
</section>
<section class="budget-dashboard">
<div class="dash-title">Dashboard</div>
<div class="toggle">
<div class="tab1 clicked">Expenses</div>
<div class="tab2">Income</div>
<!-- <div class="tab3 clicked">All</div> -->
</div>
<div class="income-tab hidden">
<ul class="list"></ul>
<div class="income-input-container">
<form class="input">
<input type="text" class="income-title-input" name="title" placeholder="Title">
<input type="number" class="income-amount-input" name="amount" placeholder="$0">
<button type = "button" class="add-income"><img class= "plus-img"src="media/Icons/icons8-add-new-48.png" alt=""></button>
</form>
</div>
</div>
<div class = "expense-tab">
<ul class="list"></ul>
<div class="expense-input-container">
<div class="input">
<input type="text" class="expense-title-input" name="title" placeholder="Title">
<input type="number" class="expense-amount-input" name="amount" placeholder="$0">
<button type="button" class="add-expense"><img class= "plus-img" src="media/Icons/icons8-add-new-48.png" alt=""></button>
</div>
</div>
</div>
</section>
</main>
<script src="JavaScript/budget.js"></script>
</body>
</html>
I've tried to use .splice() but I can't seem to get it to work.
Your entry is an object. And entry has an id property with Date type.
Your delete function calls this:
entry_list.splice(entry.id, 1)
Javascript splice function
function takes number as argument(s).
You should find the id of element you want to delete and get its index. After that you can delete the element with splice method.
Here is how to delete:
// Find the index of object at the given list
const index = entry_list.findIndex(x => x.id === entry.id);
// Starting from index of element to delete, remove 1 element.
entry_list.splice(index, 1);

Stop clicking on wrapper eventListner

I'm trying to make an open/colapse elements on this page. I'm using #wrapper::before to overlay screen, also it has a eventlistner to close elements showed. Using {capture: true} on wrapper eventListner I made it open and colapse, but when I click on search bar to type something, it colapse anyway.
How do I make it not colapse with any click? Just on the wrapper::before
const responsiveIcons = document.querySelectorAll('.mininav>*');
const wrapper = document.querySelector('#wrapper');
const mainNav = document.querySelector('aside');
const searchBar = document.querySelector('form#search');
function openItem(e){
e.classList.add('show');
wrapper.classList.add('show');
}
function closeItems(){
switch(true){
case mainNav.classList.contains('show'):
mainNav.classList.remove('show');
break;
case searchBar.classList.contains('show'):
searchBar.classList.remove('show');
break;
}
wrapper.classList.remove('show');
}
function showSelector(e){
const eClass = e.target.classList;
switch(true){
case eClass.contains('nav'):
openItem(mainNav);
break;
case eClass.contains('searchbar'):
openItem(searchBar);
break;
}
// if(e.target.classList.contains('nav')){
// openItem(mainNav);
// } else if{}
}
wrapper.addEventListener('click', closeItems, {capture: true});
responsiveIcons.forEach(e => e.addEventListener('click', showSelector));
:root {
--font-family: "Ubuntu", sans-serif;
--font-size: 16px;
--title-color: rgb(58, 58, 58);
--background-color: white;
--bgHeader: #003459;
--bgSearchBar: #002a45;
--headers: #003459;
--bgMain: #EBF9FF;
--textColor: #00171F;
--cardGreen: rgba(157, 255, 0, 1);
--cardBlue: rgba(0, 174, 255, 1);
--cardRed: rgba(255, 42, 42, 1);
--cardYellow: rgba(255, 251, 0, 1);
--headerMargin: .5rem 0;
--box-shadow: 0 1rem 1rem -0.75rem rgb(105 96 215 / 18%);
--wrap-first-column: 14rem;
--nav-txt-color: #5c5c5c;
}
#wrapper {
display: grid;
grid-template-columns: min-content 1fr;
grid-template-rows: min-content 1fr;
background-color: var(--bgMain);
min-height: 100%;
}
#wrapper.show::before {
content: "";
position: fixed;
background-color: black;
opacity: 0.5;
z-index: 2;
width: 100%;
height: 100%;
}
header {
grid-column: span 2;
column-span: all;
background: var(--bgHeader);
justify-content: space-between;
}
.brand {
height: fit-content;
width: 12.5rem;
align-items: center;
margin: var(--headerMargin);
}
header > div + div {
height: fit-content;
width: auto;
align-items: center;
margin: var(--headerMargin);
margin: auto 0.5rem;
}
.mininav {
color: white;
width: max-content;
display: inline-block;
flex-direction: row;
flex-wrap: nowrap;
}
aside.show {
left: 0;
}
aside {
inset: 0 auto;
position: absolute;
top: 0;
left: calc(var(--wrap-first-column) * -1);
}
main {
width: inherit;
}
form#search.show {
top: 0.5rem;
}
form#search {
position: absolute;
top: -2.5rem;
left: 0;
width: 100%;
transition: top 0.15s ease-out;
}
form#search > div {
position: relative;
margin-left: 10px;
}
<div id="wrapper">
<!-- Full container grid -->
<header class="flex">
<div class="brand flex">
<img src="./images/logo-cp-admin.png" alt="" class="">
</div>
<div class="flex">
<!-- search bar -->
<form id="search" action="#" method="get">
<div class=" align-top">
<input id="searchbar" type="search" placeholder=" "
class="text-xs focus:outline-none bg-bgSearchBar/[.0] focus:bg-bgSearchBar/50 text-white p-1.5 pl-3 pr-6 my-0.5 rounded-xl">
<label for="searchbar">Busca...</label>
<span class="mdi mdi-magnify"></span>
</div>
</form>
</div>
<!-- mobile responsive -->
<div class="mininav flex" >
<label class="searchbar mdi mdi-magnify">MAGNIFY</label>
<label class="nav mdi mdi-menu">HAM-MENU
</div>
</header>
<div class="flex col-span2">
<!-- side content (menu & widgets)-->
<aside>
side
</aside>
<main>
main
</main>
</div>
Two things needed to be changed.
First, the closeItems() function needs to be changed to accept an event, and to ignore clicks on the search bar.
Second, the #wrapper.show::before rule needs to not have z-index: 2 which was making the search bar appear below the ::before element and impossible to click on.
const responsiveIcons = document.querySelectorAll('.mininav>*');
const wrapper = document.querySelector('#wrapper');
const mainNav = document.querySelector('aside');
const searchBar = document.querySelector('form#search');
function openItem(e){
e.classList.add('show');
wrapper.classList.add('show');
}
function closeItems(e){
if(e.target.id == 'searchbar')
return;
switch(true){
case mainNav.classList.contains('show'):
mainNav.classList.remove('show');
break;
case searchBar.classList.contains('show'):
searchBar.classList.remove('show');
break;
}
wrapper.classList.remove('show');
}
function showSelector(e){
const eClass = e.target.classList;
switch(true){
case eClass.contains('nav'):
openItem(mainNav);
break;
case eClass.contains('searchbar'):
openItem(searchBar);
break;
}
// if(e.target.classList.contains('nav')){
// openItem(mainNav);
// } else if{}
}
wrapper.addEventListener('click', closeItems, {capture: true});
responsiveIcons.forEach(e => e.addEventListener('click', showSelector));
:root {
--font-family: "Ubuntu", sans-serif;
--font-size: 16px;
--title-color: rgb(58, 58, 58);
--background-color: white;
--bgHeader: #003459;
--bgSearchBar: #002a45;
--headers: #003459;
--bgMain: #EBF9FF;
--textColor: #00171F;
--cardGreen: rgba(157, 255, 0, 1);
--cardBlue: rgba(0, 174, 255, 1);
--cardRed: rgba(255, 42, 42, 1);
--cardYellow: rgba(255, 251, 0, 1);
--headerMargin: .5rem 0;
--box-shadow: 0 1rem 1rem -0.75rem rgb(105 96 215 / 18%);
--wrap-first-column: 14rem;
--nav-txt-color: #5c5c5c;
}
#wrapper {
display: grid;
grid-template-columns: min-content 1fr;
grid-template-rows: min-content 1fr;
background-color: var(--bgMain);
min-height: 100%;
}
#wrapper.show::before {
content: "";
position: fixed;
background-color: black;
opacity: 0.5;
width: 100%;
height: 100%;
}
header {
grid-column: span 2;
column-span: all;
background: var(--bgHeader);
justify-content: space-between;
}
.brand {
height: fit-content;
width: 12.5rem;
align-items: center;
margin: var(--headerMargin);
}
header > div + div {
height: fit-content;
width: auto;
align-items: center;
margin: var(--headerMargin);
margin: auto 0.5rem;
}
.mininav {
color: white;
width: max-content;
display: inline-block;
flex-direction: row;
flex-wrap: nowrap;
}
aside.show {
left: 0;
}
aside {
inset: 0 auto;
position: absolute;
top: 0;
left: calc(var(--wrap-first-column) * -1);
}
main {
width: inherit;
}
form#search.show {
top: 0.5rem;
}
form#search {
position: absolute;
top: -2.5rem;
left: 0;
width: 100%;
transition: top 0.15s ease-out;
}
form#search > div {
position: relative;
margin-left: 10px;
}
<div id="wrapper">
<!-- Full container grid -->
<header class="flex">
<div class="brand flex">
<img src="./images/logo-cp-admin.png" alt="" class="">
</div>
<div class="flex">
<!-- search bar -->
<form id="search" action="#" method="get">
<div class=" align-top">
<input id="searchbar" type="search" placeholder=" "
class="text-xs focus:outline-none bg-bgSearchBar/[.0] focus:bg-bgSearchBar/50 text-white p-1.5 pl-3 pr-6 my-0.5 rounded-xl">
<label for="searchbar">Busca...</label>
<span class="mdi mdi-magnify"></span>
</div>
</form>
</div>
<!-- mobile responsive -->
<div class="mininav flex" >
<label class="searchbar mdi mdi-magnify">MAGNIFY</label>
<label class="nav mdi mdi-menu">HAM-MENU
</div>
</header>
<div class="flex col-span2">
<!-- side content (menu & widgets)-->
<aside>
side
</aside>
<main>
main
</main>
</div>

Attempting to run Images through a Loop Displaying Each in turn (Dice Roll). QuerySelector Failing

Assignment
I am a software development student and have been tasked with a dice game assignment. I wanted to add simulate a die roll by looping through and array, displaying each image (die faces 1 - 5) in turn.
Problems I am Facing
When I call this function the die doesn't act any differently than usual. I am getting errors in the console stating that 'animate' is null. Leading me to the conclusion that the issue lies in the querySelector which also returns null.
Error: "dice.js:18 Uncaught TypeError: Cannot set property 'innerHTML'
of null
at imageLoop (dice.js:18)
at HTMLButtonElement.<anonymous> (dice.js:62)"
What I have tried
My first approach to the problem was staring at my screen intensely, to the dulcet tones of Pink Floyd. Hours later, when my eyes started to hurt, I attempted a different syntax, not knowing the code above wasn't returning. Since diagnosing the problem through the console, I have check over all of my code looking for the issue, but I can't find it.
Here's the code snippet of what I had on line 18. I have a strong feeling I am barking up the wrong tree but I can't think of anything else to do
animate.innerHTML += '<img src=\"'+imgArr[i]+'\">';
I have also tried the medium of expressive dance, toe stretches and gazing to the skies with inspirational music playing; not unlike they do in the movies.
What I Need
Being a student, I really need to understand what has gone wrong as opposed to direct answers with no explanation.
My Code
This is my first post, so I apologise if I have the formatting wrong. Please let me know if there's anything I can improve on.
function imageLoop (){
let img1 = document.getElementById('die1');
let img2 = document.getElementById('die2');
let img3 = document.getElementById('die3');
let img4 = document.getElementById('die4');
let img5 = document.getElementById('die5');
let img6 = document.getElementById('die6');
// declare array
let imgArr = ['img1', 'img2', 'img3', 'img4', 'img5', 'img6'];
// do something with it
// problematic code below
i=0;
while(i < 10){
let windowRoll = document.getElementById('windowDie');
let animate = windowRoll.querySelector('p');
console.log(animate);
animate.innerHTML = imgArr[i];
console.log(i);
i++;
}
}
// problematic code above
function roll(){
let x = Math.floor(Math.random() * 6) +1;
let box = document.getElementById("windowDie");
console.log(x);
document.getElementById('rollSound').pause();
document.getElementById('rollSound').currentTime = 0;
document.getElementById('rollSound').play();
if(x === 1){
let target = box.querySelector('p');
box.innerHTML = `<img src="images/die1.png"> `;
}
else if(x === 2){
let target = box.querySelector('p');
box.innerHTML = `<img src="/images/die2.png"> `;
}
else if(x === 3){
let target = box.querySelector('p');
box.innerHTML = `<img src="/images/die3.png"> `;
}
else if(x === 4){
let target = box.querySelector('p');
box.innerHTML = `<img src="/images/die4.png"> `;
}
else if(x === 5){
let target = box.querySelector('p');
box.innerHTML = `<img src="/images/die5.png"> `;
}
else if(x === 6){
let target = box.querySelector('p');
box.innerHTML = `<img src="/images/die6.png"> `;
}
return x;}
let submit = document.getElementById('submit');
submit.addEventListener("click", () =>{
roll();
imageLoop();
})
*{
padding: 0%;
margin: 0%;
}
body{
background-image: url('/images/bg.jpg');
}
.header{
padding: 3vh 6vh 1vh 6vh;
max-width: 100vw;
height: 10vh;
background-color: rgba(228, 15, 15, 0.514);
color:wheat;
font-family: 'Lobster', cursive;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.options{
display: flex;
flex-direction: row;
align-items: flex-end;
min-width: 30vw;
justify-content: space-between;
margin: 1vh 1vh 5vh 1vh;
border-right: black 1vh;
}
.wrapper{
display: flex;
justify-content: space-around;
}
.left-container{
width: 30vw;
height: 30vw;
}
.right-container{
display: flex;
width: 40vw;
height: 40vw;
flex-direction: row;
margin-left: 5vh;
justify-content: space-around;
}
.playerOne{
min-width: 40%;
min-height: 50%;
background-color: purple;
border-radius: 1vh 1vh 1vh 1vh;
align-items: center;
justify-content: space-around;
align-content: center;
text-align: center;
background-color: rgba(71, 6, 50, 0.767);
text-decoration: white underline;
padding-top: 1vh;
}
.playerTwo{
min-width: 40%;
min-height: 50%;
background-color: rgba(71, 6, 50, 0.767);
border-radius: 1vh 1vh 1vh 1vh;
align-items: center;
margin-right: 1vh;
padding-top: 1vh;
}
.window{
height: 30vh;
width: auto;
background-color: purple;
border-radius: 1vh 1vh 1vh 1vh;
align-items: center;
justify-content: space-around;
object-fit: cover;
text-align: center;
background-color: rgba(71, 6, 50, 0.767);
text-decoration: white underline;
padding-top: 1vh;
margin-top: 1vh;
display: flex;
}
img{
max-width: 90%;
max-height: 90%;
}
.box{
background-color:rgba(228, 15, 15, 0.404);
margin-top: 5vh;
color:wheat;
font-family: 'Lobster', cursive;
padding:1vh 2vh 2vh 2vh;
margin-left: 5vh;
margin-right: 5vh;
max-height: 60vh;
margin-bottom: 5vh;
align-content: center;
text-align: center;
text-decoration: white underline;
box-shadow: rgba(0, 0, 0, 0.459) 2vh 2vh;
}
.middle-container{
height: 40vh;
width: 40vh;
color:wheat;
font-family: 'Lobster', cursive;
box-shadow: rgba(0, 8, 8, 0.658) 1vh 1vh 0;
}
.button{
margin-top: 10vh;
min-width: 20vw;
min-height: 10vh;
background-image: linear-gradient(purple, black);
border-radius: 2vh 2vh 2vh 2vh;
border-style: groove;
color: wheat;
font-size: large;
box-shadow: rgba(0, 0, 0, 0.527) 2vh 2vh;
}
.button:active{
background-image: linear-gradient(yellow, black);
}
.imgLoopImages{
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Lobster&display=swap" rel="stylesheet">
<meta charset="UTF-8">
<link rel="stylesheet" href="styles/styles.css">
<title>Dice Game</title>
</head>
<div class="header">
<h1>Dice Game - Code Nation</h1>
<div class="options">
<div class="headOption">About</div>
<div class="headOption">Contact</div>
<div class="headOption">How to Play</div>
</div>
</div>
<div class="wrapper">
<div class="box left-container">
<h2>How to Play</h2>
</div>
<div class="box middle-container" id="show">
<h2>Dice Window</h2>
<div class="window" id ="windowDie"></div>
<div>
<button type="button" id="submit" class="button">Roll</button>
</div>
</div>
<div class="box right-container">
<div class="playerOne">Player One</div>
<div class="playerTwo">Player Two</div>
</div>
</div>
<div class="imgLoopImages">
<image src="/images/die1.png" id="die1"></image>
<image src="/images/die2.png" id="die2"></image>
<image src="/images/die3.png" id="die3"></image>
<image src="/images/die4.png" id="die4"></image>
<image src="/images/die5.png" id="die5"></image>
<image src="/images/die6.png" id="die6"></image>
</div>
<audio src="/sounds/die.wav" id="rollSound"></audio>
<script src="/scripts/dice.js"></script>
</body>
</html>
I think the problem is simple. In this part of your code :
while(i < 10){
let windowRoll = document.getElementById('windowDie');
let animate = windowRoll.querySelector('p');
console.log(animate);
animate.innerHTML = imgArr[i];
console.log(i);
i++;
}
You first select the element with the id "windowDie", and then try to select one paragraphe in it with windowRoll.querySelector('p'). But in your html code, I don't see any <p> </p> tag inside the element which id is "windowDie". Try adding <p> </p> inside the div which id is windowDie, like that :<div class="window" id ="windowDie"><p> </p></div>.
In case you don't know, querySelector() allows you to select htmlElements more easily than the methods getElementBy... do. You can see how it works here.

How to append a string onto innerText of a Number in JavaScript for an animated counter

I've built a ticker/counter animation with basic HTML, CSS and JavaScript and it is working well. This is for a website to show how performance and cashflow has improved when using a service so where I currently have it working and counting up to my target number, I want to append a string onto the end of these targets at the end so instead of (for example), the final target showing 35, I want it to show '35%' or for another element, '2.5x'.
I essentially want to append either a '%' onto the end if its a whole number, and if its a decimal, I want to append a 'x'.
The problem I'm having is that when I try at the end to append one of these strings onto my counter, it ruins everything and just keeps returning 0.01% instead of my target number which is 35, 70, 20 etc.
If I try to add counter.innerText = Math.ceil(count + inc) + '%' for instance, it breaks everything! I've tried to add .toString() to the end too, and then append the '%' but again the same.
These are my files, I'm sure I'm making a silly mistake somewhere so any help would be greatly appreciated!
HTML:
<div class="ticker-container">
<h1 class='ticker-header'>The Superpowers of Inclusion & Diversity are clear</h1>
</div>
<section class='counters'>
<div class='counter-container'>
<div class='num-container'>
<div class="counter" data-target='35'>0</div>
<h4 class='count-subheader'>Better financial performance</h4>
<p class='tick-p'>McKinsey</p>
</div>
<div class='num-container'>
<div class="counter" data-target='70'>0</div>
<h4 class='count-subheader'>More revenue from innovation</h4>
<p class='tick-p'>BCG</p>
</div>
<div class='num-container'>
<div class="counter" data-target='20'>0</div>
<h4 class='count-subheader'>Higher revenue</h4>
<p class='tick-p'>BCG</p>
</div>
<div class='num-container'>
<div class="counter" data-target='2.5'>0</div>
<h4 class='count-subheader'>Higher cashflow per employee</h4>
<p class='tick-p'>HBR</p>
</div>
</div>
</section>
CSS:
#import url('https://fonts.googleapis.com/css2?family=Rubik:wght#400;500;700;');
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Roboto', sans-serif;
background-image: linear-gradient(to right, #923CC7 , #B978E1);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.counter-container {
max-width: 1200px;
margin: 0 auto;
overflow: auto;
}
.ticker-container {
flex: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.ticker-header {
font-size: 48px;
margin-top: 20px;
}
.counters {
padding: 50px 20px;
}
.counter-container {
display: grid;
grid-gap: 40px;
grid-template-columns: repeat(4, 1fr);
text-align: center;
}
.counter {
font-size: 55px;
margin: 10px 0;
background-color: white;
border-radius: 50%;
width: 120px;
height: 120px;
display: flex;
justify-content: center;
align-items: center;
}
.count-subheader {
font-size: 17px;
margin-top: 25px;
}
.tick-p {
color: white;
margin-top: 20px;
}
.num-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#media(max-width: 700px) {
.counter-container {
grid-template-columns: repeat(2, 1fr);
}
}
JavaScript:
const counters = document.querySelectorAll('.counter');
const speed = 200;
const decSpeed = 30;
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText;
const inc = target / speed;
const decInc = target / decSpeed;
if (count < target && target % 1 === 0) {
counter.innerText = Math.ceil(count + inc)
setTimeout(updateCount, 1);
} else if (count < target && target % 1 !== 0) {
counter.innerText = (count + decInc).toFixed(1)
setTimeout(updateCount, 1);
} else {
count.innerText = target;
}
}
updateCount();
})
The problem is this line:
const count = +counter.innerText;
once you add a symbol to the innerText, next time this won't return a proper number (NaN).
You can fix it by removing the symbol part before casting to number:
const count = +counter.innerText.slice(0, -1);
const counters = document.querySelectorAll('.counter');
const speed = 200;
const decSpeed = 30;
counters.forEach(counter => {
const updateCount = () => {
const target = +counter.getAttribute('data-target');
const count = +counter.innerText.slice(0, -1);
const inc = target / speed;
const decInc = target / decSpeed;
if (count < target && target % 1 === 0) {
counter.innerText = Math.ceil(count + inc) + '%'
setTimeout(updateCount, 1);
} else if (count < target && target % 1 !== 0) {
counter.innerText = (count + decInc).toFixed(1) + 'x';
setTimeout(updateCount, 1);
} else {
count.innerText = target;
}
}
updateCount();
})
#import url('https://fonts.googleapis.com/css2?family=Rubik:wght#400;500;700;');
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Roboto', sans-serif;
background-image: linear-gradient(to right, #923CC7, #B978E1);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.counter-container {
max-width: 1200px;
margin: 0 auto;
overflow: auto;
}
.ticker-container {
flex: 1;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.ticker-header {
font-size: 48px;
margin-top: 20px;
}
.counters {
padding: 50px 20px;
}
.counter-container {
display: grid;
grid-gap: 40px;
grid-template-columns: repeat(4, 1fr);
text-align: center;
}
.counter {
font-size: 55px;
margin: 10px 0;
background-color: white;
border-radius: 50%;
width: 120px;
height: 120px;
display: flex;
justify-content: center;
align-items: center;
}
.count-subheader {
font-size: 17px;
margin-top: 25px;
}
.tick-p {
color: white;
margin-top: 20px;
}
.num-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#media(max-width: 700px) {
.counter-container {
grid-template-columns: repeat(2, 1fr);
}
}
<div class="ticker-container">
<h1 class='ticker-header'>The Superpowers of Inclusion & Diversity are clear</h1>
</div>
<section class='counters'>
<div class='counter-container'>
<div class='num-container'>
<div class="counter" data-target='35'>0</div>
<h4 class='count-subheader'>Better financial performance</h4>
<p class='tick-p'>McKinsey</p>
</div>
<div class='num-container'>
<div class="counter" data-target='70'>0</div>
<h4 class='count-subheader'>More revenue from innovation</h4>
<p class='tick-p'>BCG</p>
</div>
<div class='num-container'>
<div class="counter" data-target='20'>0</div>
<h4 class='count-subheader'>Higher revenue</h4>
<p class='tick-p'>BCG</p>
</div>
<div class='num-container'>
<div class="counter" data-target='2.5'>0</div>
<h4 class='count-subheader'>Higher cashflow per employee</h4>
<p class='tick-p'>HBR</p>
</div>
</div>
</section>

How do I give elements with the same class name to perform the same function in javascript?

I have multiple elements with the same class name and want them to perform the same javascript function but output their unique "inner.Text" specific
to the element i clicked. Right Now i know i need an [index] and a loop
but I just don't know how to implement that at the moment since im a novice in javascript.
spent 3 hours trying to figure it out
const myButton = document.querySelectorAll('.clipboard-icon');
const myInp = document.querySelectorAll('.snippetcode');
myButton.forEach(ree =>
ree.addEventListener('click', copyElementText));
function copyElementText(id) {
var text = myInp.innerText;
var elem = document.createElement("textarea");
document.body.appendChild(elem);
elem.value = text;
elem.select();
document.execCommand("copy");
document.body.removeChild(elem);
console.log('clicked');
}
console.log(myButton);
console.log(myInp);
/*everything works fine if the script was changed to affect only ONE class name but I cant figure out how to make them work for more than one
*/
.snippet1 {
border: solid rgb(55, 63, 184) 3px;
}
.snippet_holder {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
padding: 0 3.5rem;
margin: 0 0 1rem 0;
position: relative;
}
.buttons {
width: 170px;
height: 40px;
border: 0;
padding: 0;
font-size: 1rem;
color: #fff;
border-radius: 10px;
}
.snippet_holder:hover .clipboard-icon {
display: block;
position: absolute;
top: 15px;
right: 65px;
background: rgb(51, 153, 136);
margin: 0;
width: 30px;
padding: 0;
height: 30px;
}
.clipboard-icon {
display: none;
}
.clipboard-icon img {
width: inherit;
height: inherit;
position: relative;
}
.clipboard-icon pre {
display: none;
}
.snippetcode1 {
display: none;
}
.button1 {
-webkit-animation: rainbow 6.5s ease infinite;
animation: rainbow 6.5s ease infinite;
background-image: linear-gradient(124deg, #ff470f, #ff3860, #b86bff, #3273dc);
background-size: 800% 800%;
}
#keyframes rainbow {
0% {
background-position: 1% 80%;
}
50% {
background-position: 99% 20%;
}
100% {
background-position: 1% 80%;
}
0% {
background-position: 1% 80%;
}
50% {
background-position: 99% 20%;
}
100% {
background-position: 1% 80%;
}
}
main {
margin: 0 auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
<html>
<body>
<main>
<div class="snippet_holder snippet_holder1">
<div class="clipboard-icon">
<pre>
<code class= "snippetcode">
1st class text copieddddd
</code>
</pre>
<img src="https://www.shareicon.net/data/128x128/2016/04/27/756265_clipboard_512x512.png">
</div>
<button type="button" class="buttons button1">button</button>
</div>
<div class="snippet_holder snippet_holder1">
<div class="clipboard-icon">
<pre>
<code class= "snippetcode">
22222nddd class text copieddddd
</code>
</pre>
<img src="https://www.shareicon.net/data/128x128/2016/04/27/756265_clipboard_512x512.png">
</div>
<button type="button" class="buttons button1">button</button>
</div>
<div class="snippet_holder snippet_holder1">
<div class="clipboard-icon">
<pre>
<code class= "snippetcode">
3rd class text copieddddd
</code>
</pre>
<img src="https://www.shareicon.net/data/128x128/2016/04/27/756265_clipboard_512x512.png">
</div>
<button type="button" class="buttons button1">button</button>
</div>
<div class="snippet_holder snippet_holder1">
<div class="clipboard-icon">
<pre>
<code class= "snippetcode">
4thhhhhhhhclass text copieddddd
</code>
</pre>
<img src="https://www.shareicon.net/data/128x128/2016/04/27/756265_clipboard_512x512.png">
</div>
<button type="button" class="buttons button1">button</button>
</div>
</main>
</body>
</html>
You've to query the .snippetcode related to the button pressed, so, it makes no sense to query the nodeList myInp, you can access to the right element using the currentTarget provided in the event object...
function copyElementText(event) {
var text = event.currentTarget.querySelector('.snippetcode').innerText;
var elem = document.createElement("textarea");
document.body.appendChild(elem);
elem.value = text;
elem.select();
document.execCommand("copy");
document.body.removeChild(elem);
console.log('clicked');
}

Categories