onclick event not picking up className elements to append - showing error - javascript

I am not sure why my code is not picking up my selections and appending then to my array when the submit button is clicked. I am getting the following error...
"modals.js:103 Uncaught TypeError: Cannot read properties of null (reading 'length') at submit_button.onclick"
My code adds 'button focus' to the className when selected.
I want to take those selections and append them to my an array.
For some reason it does not detect any elements with the className of '.btn.button-focus'.
Any ideas?
var container = document.getElementById('my_dataviz');
var array = ["One", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten"
]
let identifier = 0;
let SelectCount = 0;
array.forEach(element => {
const button = document.createElement("button");
button.className = "btn";
button.id = element;
button.value = element;
button.type = "button";
const text = document.createTextNode(element);
button.appendChild(text);
container.appendChild(button);
});
let btn = document.getElementsByClassName("btn");
for (let i = 0; i < btn.length; i++) {
(function(index) {
btn[index].addEventListener("click", function() {
console.log("Clicked Button: " + index);
let isPresent = false;
this.classList.forEach(function(e, i) {
if (e == "button-focus") {
isPresent = true;
} else {
isPresent = false;
}
});
if (isPresent) {
this.classList.remove("button-focus");
SelectCount -= 1;
document.querySelectorAll('.btn').forEach(item => {
if (!item.classList.value.includes('button-focus')) item.disabled = false
})
} else {
this.classList.add("button-focus");
SelectCount += 1;
if (SelectCount > 2) {
document.querySelectorAll('.btn').forEach(item => {
if (!item.classList.value.includes('button-focus')) item.disabled = true
})
}
}
})
})(i)
}
const dataResults = []
let results = document.querySelector('.btn.button-focus');
let submit_button = document.querySelector('.modal-btn');
submit_button.onclick = function() {
for (let i = 0; i < results.length; ++i) {
dataResults.push(results)
console.log(results)
}
}
:root {
--primary_orange: #fea501;
}
.my_dataviz {
width: auto;
height: auto;
margin-top: 15px;
margin-bottom: 15px;
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: space-evenly;
}
.my_dataviz button {
font-family: "walkway";
font-size: 16px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
width: 130px;
height: 25px;
background-color: Transparent;
-webkit-tap-highlight-color: transparent;
background-repeat:no-repeat;
border: none;
letter-spacing: 1.6px;
margin: 10px;
border: 1px solid transparent;
}
.my_dataviz button:hover {
box-sizing: border-box;
background-color: var(--primary_orange);
color: var(--dark);
font-weight: bold;
border: 1px solid #000;
border-radius: 5px;
cursor: pointer;
/*box-shadow: var(--shadow);*/
}
.btn.button-focus {
background-color: var(--primary_orange);
color: var(--dark);
font-weight: bold;
border: 1px solid #000;
border-radius: 5px;
}
.modal-footer {
display: flex;
flex-wrap: wrap;
justify-content: center;
height: 50px;
align-items: center;
text-align: center;
background: var(--primary_med);
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.modal-footer .modal-btn {
font-family: "walkway";
font-size: 16px;
font-weight: bold;
width: 100px;
height: 28px;
border-radius: 5px;
align-items: center;
letter-spacing: 1.6px;
box-shadow: var(--shadow);
}
<div class="my_dataviz" id="my_dataviz">
</div>
<div class="modal-footer">
<input class="modal-btn" type="button" value="Select it" />
</div>

It should run querySelector when the user presses the submit button.
const dataResults = []
let results = document.querySelector('.btn.button-focus'); // remove this line
let submit_button = document.querySelector('.modal-btn');
submit_button.onclick = function() {
dataResults = document.querySelectorAll('.btn.button-focus') // Edit
console.log(dataResults)
}
}

submit_button.onclick = function() {
if(results == null) return;
for (let i = 0; i < results.length; ++i) {
dataResults.push(results)
console.log(results)
}
}
querySelector returns null if it didn't find wanted elements.
But what you want anyways is change querySelector to querySelectorAll and use this code then:
submit_button.onclick = function() {
if(results.length == 0) return;
for (let i = 0; i < results.length; i++) {
dataResults.push(results[i])
console.log(results[i])
}
}
(I made multiple changes to your code which changed the functionality according to what I think you wanted to do (I didn't read what is your purpose in the code))

Related

Is there any other way to sort a drag and drop todo list without using the index of the items?

I'm working on a javascript to-do list where you can view all the elements on the list or you can view just the active items or the completed items.
Each of the views has its own array which I sorted out using the index of each element
but when I reorder the list on one of the views, the change is not implemented in the other views.
How do I rectify this?
const dragArea1 = document.querySelector('#task1');
const dragArea2 = document.querySelector('#task2');
const dragArea3 = document.querySelector('#task3');
const addnew = document.querySelector('[name="addnew"]')
const add = document.querySelector('[name="new"]')
const countIt = document.querySelector('#count')
var all = [];
var active = [];
var complete = [];
var lists = document.querySelectorAll('ul');
var views = document.querySelectorAll('.action .views a');
var mobileViews = document.querySelectorAll('#views a');
var list = document.querySelector('.list');
countIt.innerHTML = active.length;
addnew.addEventListener('click', () => {
var newItem
if (addnew.checked == true) {
newItem = {
val: add.value,
checked: false
}
all.push(newItem);
active.push(newItem);
window.setTimeout(() => {
addnew.checked = false;
add.value = '';
}, 300);
displayAll();
count();
}
})
list.addEventListener('click', (ev) => {
if (ev.target.tagName === 'LABEL' || ev.target.tagName === 'P' || ev.target.tagName === 'LI') {
ev.target.classList.toggle('checked');
sortAllList();
if (lists[1].style.display == 'block') {
activeToComplete();
}
if (lists[2].style.display == 'block') {
completeToActive();
}
sortActive();
sortComplete();
}
if (all.length == 0) {
var htmlCode = `<em style="text-align: center; width: 100%; padding: 20px;">add a todo item</em>`;
lists[0].innerHTML = htmlCode;
}
if (active.length == 0) {
var htmlCode = `<em style="text-align: center; width: 100%; padding: 20px;">add a todo item</em>`;
lists[1].innerHTML = htmlCode;
}
if (complete.length == 0) {
var htmlCode = `<em style="text-align: center; width: 100%; padding: 20px;">complete a todo item</em>`;
lists[2].innerHTML = htmlCode;
}
// console.log(ev.target.tagName);
})
function count() {
// to keep count of active items
countIt.innerHTML = active.length;
}
views[0].classList.add('view')
mobileViews[0].classList.add('view')
function displayAll() {
sortActive();
sortComplete();
var htmlCode = "";
if (all.length !== 0) {
for (let i = 0; i < all.length; i++) {
htmlCode += `
<li draggable="true">
<div class="check">
<input type="checkbox" name="listItem" id="item${i}">
<label for="item${i}"></label>
</div>
<p class="itemdesc">${all[i].val}</p>
<span onclick="del(${i})">╳</span>
</li>
`
}
lists[0].innerHTML = htmlCode;
}
lists[0].style.display = 'block';
lists[1].style.display = 'none';
lists[2].style.display = 'none';
views[0].classList.add('view')
views[1].classList.remove('view')
views[2].classList.remove('view')
mobileViews[0].classList.add('view')
mobileViews[1].classList.remove('view')
mobileViews[2].classList.remove('view')
count()
keepChecked();
}
function sortActive() {
// to add active items to the active array
var fit
fit = all.filter(el => el.checked == false)
active = fit
count();
}
function sortComplete() {
//to add completed items to the complete array
var com
com = all.filter(el => el.checked == true)
complete = com
// console.log('complete', complete);
}
function sortAllList() {
// to sort the items into active and completed
const items = document.querySelectorAll('#task1 li');
for (let i = 0; i < all.length; i++) {
if (items[i].classList.contains('checked') == true) {
all[i].checked = true
} else {
all[i].checked = false
}
}
}
function activeToComplete() {
let newA
const items = document.querySelectorAll('#task2 li')
for (let i = 0; i < active.length; i++) {
if (items[i].classList.contains('checked') == true) {
active[i].checked = true;
// active.splice(i,1);
// console.log(active.splice());
} else {
active[i].checked = false
}
}
newA = active.filter(el => el.checked !== true)
console.log(newA);
active = newA;
}
function keepChecked() {
// to keep the completed items checked afetr changing views
const allItems = document.querySelectorAll('#task1 li');
for (let i = 0; i < all.length; i++) {
if (all[i].checked == true) {
allItems[i].classList.add('checked')
}
}
}
function completeToActive() {
const items = document.querySelectorAll('#task3 li')
for (let i = 0; i < complete.length; i++) {
if (items[i].classList.contains('checked') == true) {
complete[i].checked = true;
} else {
complete[i].checked = false
complete.splice(i, 1);
console.log(complete.splice());
}
}
}
function displayActive() {
sortAllList();
sortActive();
var htmlCode = "";
if (active.length !== 0) {
for (let i = 0; i < active.length; i++) {
htmlCode += `
<li draggable="true">
<div class="check">
<input type="checkbox" name="listItem" id="item${i}">
<label for="item${i}"></label>
</div>
<p class="itemdesc">${active[i].val}</p>
<span onclick="del(${i})">╳</span>
</li>
`
}
lists[1].innerHTML = htmlCode;
}
lists[1].style.display = 'block';
lists[0].style.display = 'none';
lists[2].style.display = 'none';
views[1].classList.add('view')
views[0].classList.remove('view')
views[2].classList.remove('view')
mobileViews[1].classList.add('view')
mobileViews[0].classList.remove('view')
mobileViews[2].classList.remove('view')
count()
}
function displayCompleted() {
let unique = [...new Set(complete)]
// console.log(unique[0].val);
var htmlCode = "";
if (unique.length !== 0) {
for (let i = 0; i < unique.length; i++) {
htmlCode += `
<li draggable="true" class="checked">
<div class="check">
<input type="checkbox" name="listItem" id="item${i}">
<label for="item${i}"></label>
</div>
<p class="itemdesc">${unique[i].val}</p>
<span onclick="del(${i})">╳</span>
</li>
`
}
lists[2].innerHTML = htmlCode;
}
lists[2].style.display = 'block';
lists[1].style.display = 'none';
lists[0].style.display = 'none';
views[2].classList.add('view')
views[0].classList.remove('view')
views[1].classList.remove('view')
mobileViews[2].classList.add('view')
mobileViews[1].classList.remove('view')
mobileViews[0].classList.remove('view')
count()
}
function clearComplete() {
var htmlCode = `<em style="text-align: center; width: 100%; padding: 20px;">complete a todo item</em>`;
complete = [];
lists[2].innerHTML = htmlCode;
}
function del(theIndex) {
let i = theIndex;
if (lists[0].style.display == 'block') {
all.splice(i, 1);
displayAll();
}
if (lists[1].style.display == 'block') {
active.splice(i, 1);
let removeFromAll = all.find(el => {
el == active.splice()
})
all.splice(removeFromAll, 1);
displayActive();
}
if (lists[2].style.display == 'block') {
complete.splice(i, 1);
let removeFromAll = all.find(el => {
el == complete.splice()
})
all.splice(removeFromAll, 1);
displayCompleted();
}
sortActive();
sortComplete();
}
new Sortable(dragArea1, {
animation: 350
})
new Sortable(dragArea2, {
animation: 350
})
new Sortable(dragArea3, {
animation: 350
})
:root {
--blue: hsl(220, 98%, 61%);
/* vd -> Very Drak */
--vdblue: hsl(235, 21%, 11%);
--vdDesaturatedblue: hsl(235, 24%, 19%);
--lightgrayblue: hsl(234, 39%, 85%);
--lightgrayblueh: hsl(236, 33%, 92%);
--darkgrayblue: hsl(234, 11%, 52%);
--vdGrayishblueh: hsl(233, 14%, 35%);
--vdGrayishblue: hsl(237, 14%, 26%);
--checkbg: linear-gradient(rgba(87, 221, 255, .7), rgba(192, 88, 243, .7));
--font: 'Josefin Sans', sans-serif;
font-size: 18px;
}
* {
padding: 0;
margin: 0;
font-family: var(--font);
/* font-weight: 700; */
}
*,
*::after,
*::before {
box-sizing: border-box;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
border: none;
-webkit-text-fill-color: white;
background-color: transparent !important;
-webkit-box-shadow: 0 0 0px 1000px #00000000 inset;
transition: background-color 5000s ease-in-out 0s;
}
input:focus, input:active, input:visited, textarea:focus, textarea:active, textarea:visited{
background-color: transparent;
border: none;
outline: none;
}
a, em, span{
display: inline-block;
cursor: pointer;
}
a{
text-decoration: none;
display: inline-block;
}
header, main, footer{
width: 100%;
max-width: 30rem;
padding: 10px;
}
main {
display: flex;
flex-direction: column;
gap: 30px;
align-items: center;
}
main #new,
li {
display: flex;
align-items: center;
gap: 20px;
padding: 1rem;
width: 100%;
}
main section,
main #views {
width: 100%;
}
main section,
main #new,
main #views {
border-radius: 5px;
}
main .list {
min-height: 2.5rem;
max-height: 20rem;
/* height: 10rem; */
position: relative;
overflow-y: auto;
}
main .list ul {
/* position: absolute; */
/* top: 20px; */
width: 100%;
display: none;
}
main .list ul:nth-child(1) {
display: block;
}
main #new input[name="new"] {
padding: 10px;
height: inherit;
}
input {
background-color: transparent;
width: calc(100% - 70px);
border: none;
font-size: 1rem;
}
li {
justify-content: flex-start;
}
li .check {
position: relative;
}
main #new .check input,
li .check input {
display: none;
}
main #new .check label,
li .check label {
width: 30px;
height: 30px;
border-radius: 30px;
display: inline-block;
}
main #new .check input:checked~label,
li.checked .check label {
background-image: var(--checkbg), url(images/icon-check.svg);
background-position: center center;
background-repeat: no-repeat;
}
li p {
width: 85%;
}
li.checked label {
background-color: #66666696;
}
li.checked p {
text-decoration: line-through;
}
li span {
/* justify-self: flex-end; */
display: none;
}
li:hover span {
display: flex;
}
main .action {
display: flex;
justify-content: space-between;
/* gap: 2rem; */
padding: 1.1rem;
font-size: .8rem;
}
.views a,
#views a {
font-weight: 700;
}
.action a.view {
color: var(--blue);
}
main #views {
padding: .8rem;
text-align: center;
font-size: .8rem;
display: none;
}
#views a.view {
color: var(--blue);
}
main #views+p {
font-size: .7rem;
}
li,
em {
border-bottom: 1px solid var(--darkgrayblue);
}
li,
li p,
main .action a:hover {
color: var(--lightgrayblue);
}
a,
em,
li.checked p,
p,
span,
input,
li span {
color: var(--darkgrayblue);
}
header img {
content: url("images/icon-sun.svg");
}
main #new {
background-color: var(--vdDesaturatedblue);
}
main #new .check label,
li .check label {
border: 1px solid var(--vdGrayishblue);
}
main #new .check label:hover,
li .check label:hover {
border: 1px solid var(--vdGrayishblue);
}
main section,
main #views {
background-color: var(--vdDesaturatedblue);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.0/Sortable.min.js"></script>
<main role="main">
<div id="new">
<div class="check">
<input type="checkbox" name="addnew" id="addnew">
<label for="addnew"></label>
</div>
<input type="text" name="new" placeholder="Create a new todo...">
</div>
<section>
<div class="list">
<ul id="task1">
<em style="text-align: center; width: 100%; padding: 20px;">add a todo item</em>
</ul>
<ul id="task2">
<em style="text-align: center; width: 100%; padding: 20px;">add a todo item</em>
</ul>
<ul id="task3">
<em draggable="true" style="text-align: center; width: 100%; padding: 20px;">complete a todo item</em>
</ul>
</div>
<div class="action">
<p>
<span id="count"></span> items left
</p>
<div class="views">
All
Active
Completed
</div>
Clear Completed
</div>
</section>
<div id="views">
All
Active
Completed
</div>
<p>Drag and drop to reorder list</p>
</main>

How to reload all kinds of functions and all HTML code in JavaScript to restart a game?

Clicking on the Home button at the end of this project brings it to the beginning, but no function is reset. Level buttons are not also being enabled anew. If I enable those level buttons by writing some extra code for enabling, then the number of buttons given for each level will be doubled after selecting the level. In other words, for the first time due to selecting the basic level, there were 4 options, But when I click on the last home button and then select the medium level to play the game from the beginning, it becomes 16 options instead of 8.
//VARIABLE DECLARATION PART
let frontpage = document.querySelector(".front-page");
let playbutton = document.querySelector(".play");
let levelpage = document.querySelector(".levelpg");
let startbtn = document.querySelector(".startbtn");
let maingame = document.querySelector(".maingame");
let easybtn = document.querySelector(".easy");
let mediumbtn = document.querySelector(".medium");
let hardbtn = document.querySelector(".hard");
let nextbtn = document.querySelector(".nextbtn");
let pagecount = document.querySelector('.gamepagecount');
let getnumberdiv = document.querySelector('.numberbtn').children;
let resultpg = document.querySelector('.resultpage');
let backhome = document.querySelector('.backhome');
let finalscore = document.querySelector('.score');
let resulttext = resultpg.children[1];
let changeimg = document.querySelector('.resultpage img');
// PLAYBUTTON CLICK
playbutton.addEventListener("click", () => {
frontpage.classList.add("hidden");
levelpage.classList.remove("hidden");
levelpage.classList.add("visibility");
});
//GAME START FUNCTION
function startGame(level) {
if (level == "easy") {
mediumbtn.disabled = true;
hardbtn.disabled = true;
easybtn.disabled = true;
easybtn.classList.add('levelcolor');
startbtn.addEventListener("click", () => {
pagecount.innerHTML = `1 of 10`;
nextbtn.disabled = true
levelChange(4);
gameInterfaceChange()
mainGame(10);
//NEXTBUTTON FUNCTION
nextbtn.addEventListener('click', () => {
enableBtn(4)
pageCount(10);
mainGame(10);
})
});
}
else if (level == "medium") {
mediumbtn.disabled = true;
hardbtn.disabled = true;
easybtn.disabled = true;
mediumbtn.classList.add('levelcolor');
startbtn.addEventListener("click", () => {
pagecount.innerHTML = `1 of 15`;
nextbtn.disabled = true
levelChange(8);
gameInterfaceChange();
maingame.style.top = "20%";
mainGame(20);
//NEXTBUTTON FUNCTION
nextbtn.addEventListener('click', () => {
enableBtn(8)
pageCount(15)
mainGame(20);
})
});
}
else if (level == "hard") {
mediumbtn.disabled = true;
hardbtn.disabled = true;
easybtn.disabled = true;
hardbtn.classList.add('levelcolor');
startbtn.addEventListener("click", () => {
pagecount.innerHTML = `1 of 20`;
nextbtn.disabled = true
levelChange(12);
gameInterfaceChange();
maingame.style.top = "12%";
mainGame(30);
//NEXTBUTTON FUNCTION
nextbtn.addEventListener('click', () => {
enableBtn(12)
pageCount(20)
mainGame(30);
})
});
}
}
//PAGE SLIDING FUNCTION
function gameInterfaceChange() {
levelpage.classList.remove("hidden");
levelpage.classList.add("hidden");
maingame.classList.remove("hidden");
maingame.style.top = "25%";
maingame.classList.add("visibility");
}
// FUNCTION OF RANDOM INPUTING NUMBER IN DIV
function mainGame(maxnum) {
let numboxlen = getnumberdiv.length;
let wrongnum = Math.floor(Math.random() * maxnum) + 1;
let getnumber = [];
//DUPLICATE RANDOM NUMBER CHECKING
for (let i = 0; i < numboxlen; i++) {
let check = getnumber.includes(wrongnum);
if (check === false) {
getnumber.push(wrongnum);
}
else {
while (check === true) {
wrongnum = Math.floor(Math.random() * maxnum) + 1;
check = getnumber.includes(wrongnum);
if (check === false) {
getnumber.push(wrongnum);
}
}
}
}
// NUMBER PUTTING IN InnerHtml
for (var j = 0; j < numboxlen; j++) {
if (getnumber[j] < 10) {
getnumberdiv[j].innerHTML = '0' + getnumber[j];
}
else {
getnumberdiv[j].innerHTML = getnumber[j];
}
}
}
// BUTTON ADDING ACCORDING TO THE LEVEL
function levelChange(divnum) {
for (let index = 0; index < divnum; index++) {
let newBtn = document.createElement('button');
let newbtnNode = document.createTextNode('');
newBtn.appendChild(newbtnNode);
let gamebtn = document.getElementById('numbrbtn');
gamebtn.appendChild(newBtn);
newBtn.setAttribute("onclick", `numberClick(${index},${divnum})`);
}
}
//RIGHT - WRONG CHECKING FUNTION
var right = 0;
var wrong = 0;
function numberClick(index, divnum) {
let rightnumberindex = Math.floor(Math.random() * divnum);
if (index == rightnumberindex) {
nextbtn.disabled = false
right++;
//RIGHT AND WRONG BACKGROUND ADDING AND BUTTON DISABLE
getnumberdiv[index].classList.add("rightans");
for (let i = 0; i < divnum; i++) {
getnumberdiv[i].disabled = true;
}
}
else {
nextbtn.disabled = false
wrong++;
//RIGHT AND WRONG BACKGROUND ADDING AND BUTTON DISABLE
getnumberdiv[rightnumberindex].classList.add("rightans");
getnumberdiv[index].classList.add("wrongans");
for (let i = 0; i < divnum; i++) {
getnumberdiv[i].disabled = true;
}
}
}
// BUTTON ENABLE ON NEXT BUTTION CLICK
function enableBtn(divnum) {
for (let i = 0; i < divnum; i++) {
nextbtn.disabled = true
getnumberdiv[i].disabled = false;
getnumberdiv[i].classList.remove("wrongans");
getnumberdiv[i].classList.remove("rightans");
}
}
//PAGE COUNTING ACCORDING TO THE LEVEL
let currentpg = 1;
function pageCount(levelPg) {
currentpg++;
if (currentpg <= levelPg) {
if (currentpg == levelPg) {
nextbtn.innerHTML = 'Result'
pagecount.innerHTML = `${currentpg} of ${levelPg}`;
}
else {
pagecount.innerHTML = `${currentpg} of ${levelPg}`;
}
}
else {
result();
}
}
//FINAL RESULT FUNTION
function result() {
maingame.classList.remove("visibility");
maingame.classList.add("hidden");
resultpg.classList.remove('hidden')
resultpg.classList.add('visibility')
if (right > wrong) {
changeimg.setAttribute('src', 'trophy.png')
resulttext.innerHTML = `You Win`;
finalscore.innerHTML = `Your Right Score is : ${right} out of ${right + wrong}`;
}
else if (right == wrong) {
changeimg.setAttribute('src', 'draw.png')
resulttext.innerHTML = `It's Draw`;
finalscore.innerHTML = `Your Right Score is : ${right} out of ${right + wrong}`;
}
else if (right < wrong) {
changeimg.setAttribute('src', 'lose.png')
resulttext.innerHTML = `You Lose`;
finalscore.innerHTML = `Your Right Score is : ${right} out of ${right + wrong}`;
}
}
//BACK TO THE HOME FUNCTION
backhome.addEventListener('click', () => {
frontpage.classList.add("visibility");
frontpage.classList.remove("hidden");
resultpg.classList.add('hidden')
resultpg.classList.remove('visibility')
// enable level button
mediumbtn.disabled = false;
hardbtn.disabled = false;
easybtn.disabled = false;
})
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
body {
margin-top: 50px;
}
.guessing-game {
position: relative;
color: white;
text-align: center;
margin: auto;
width: 350px;
height: 600px;
border-radius: 25px;
padding: 50px 30px;
background: linear-gradient(to right, #bd3f32, #cb356b);
}
.guessing-game .front-page .front-img {
height: 160px;
text-align: center;
}
.guessing-game .front-page img {
max-height: 100%;
}
.guessing-game .front-page .front-text h1 {
margin-top: 50px;
font-size: 1.8em;
}
.guessing-game .front-page .front-text p {
margin-top: 10px;
font-size: 1em;
}
.guessing-game .front-page .front-text button,
.resultpage button ,
.levelpg .easy,
.levelpg .medium,
.levelpg .hard,
.maingame .nextbtn {
margin-top: 30px;
width: 100%;
color: white;
padding: 15px;
outline: 0;
border: 0;
border-radius: 50px;
font-size: 0.9em;
background-color: #d64d5d;
box-shadow: rgba(17, 17, 26, 0.1) 0px 1px 0px,
rgba(17, 17, 26, 0.144) 0px 8px 24px, rgba(17, 17, 26, 0.1) 0px 16px 48px;
}
.guessing-game .front-page .front-text button:hover,
.maingame .nextbtn:hover,
.resultpage button:hover {
transition: 0.5s;
background-color: #c22f40;
}
/* Level page */
.visiblepg {
position: absolute;
top: 12%;
width: 290px;
}
.levelpg h1 {
margin: 45px 0 40px 0;
font-weight: 600;
font-size: 2.4em;
border: 1px solid white;
}
.levelpg .easy,
.levelpg .medium,
.levelpg .hard {
display: block;
margin-top: 15px;
padding: 12px;
background: white;
font-size: 1em;
border-radius: 10px;
font-weight: 400;
color: #c22f40;
}
.startbtn {
background: transparent;
border: 0;
outline: 0;
}
.levelpg i {
color: white;
margin-top: 50px;
font-size: 70px;
border-radius: 50%;
border: 2px solid transparent;
}
.levelpg i:hover {
background-color: white;
border: 2px solid white;
color: #c22f40;
transition: 0.5s;
}
/* GAME PART */
.maingame .gamepagecount {
background-color: #d64d5d;
color: white;
padding: 4px;
border-radius: 6px;
font-size: 0.8em;
font-weight: 600;
}
.maingame .gametext {
margin-top: 15px;
font-size: 1.2em;
}
.maingame .numberbtn {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
.maingame .numberbtn button {
margin-top: 40px;
width: 50px;
height: 50px;
background-color: white;
display: flex;
align-content: space-around;
justify-content: center;
align-items: center;
flex-wrap: wrap;
flex: 1 0 21%;
margin-left: 10px;
border: 0;
outline: 0;
border-radius: 10px;
font-size: 1em;
color: #c22f40;
font-weight: 600;
}
.maingame .numberbtn button:nth-child(1),
.maingame .numberbtn button:nth-child(5),
.maingame .numberbtn button:nth-child(9) {
margin-left: 0;
}
.resultpage h1 {
margin: 0px 0 40px 0;
}
.resultpage img {
margin-top: 45px;
width: 50%;
}
/* PRE DEFINE CSS */
.visibility {
visibility: visiible;
opacity: 2s;
transition: 0.5s;
transform: translateX(0px);
}
.hidden {
visibility: hidden;
opacity: 0;
transition: 0.5s;
transform: translateX(-30px);
}
.levelcolor {
transition: 0.5s;
color: white !important;
background-color: #c22f40 !important;
}
.rightans {
background-color: #27ae60 !important;
color: white !important;
transition: 0.5s;
}
.wrongans {
background-color: #fd4631 !important;
color: white !important;
transition: 0.5s;
}
<!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="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght#0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
rel="stylesheet" />
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css"
integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous" />
<title>Guessing Game</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="guessing-game">
<div class="front-page">
<div class="front-img">
<img src="./question.png" alt="" />
</div>
<div class="front-text">
<h1>Guessing Game</h1>
<p>
You just need to chose the right number from the option. If your
guess is right more than wrong , you will win otherwise you will
fail! Let's see how good your sixth sense is!!!
</p>
<button class="play">Let's play</button>
</div>
</div>
<div class="levelpg hidden visiblepg">
<h1>Game level</h1>
<button class="easy" onclick="startGame('easy')">Easy</button>
<button class="medium" onclick="startGame('medium')">Medium</button>
<button class="hard" onclick="startGame('hard')">Hard</button>
<button class="startbtn"><i class="fas fa-play-circle"></i></button>
</div>
<div class="maingame visiblepg hidden">
<p class="gamepagecount">1</p>
<p class="gametext">Guess the number you think is right</p>
<div class="numberbtn" id="numbrbtn"></div>
<button class="nextbtn">Next</button>
</div>
<div class="resultpage levelpg hidden visiblepg">
<img src="" alt="" />
<h1></h1>
<div class="score"></div>
<button class="backhome">Home</button>
</div>
</div>
<script src="./main.js"></script>
</body>
</html>
In short, as soon as I click on the home button, I want the game to start anew, all the functions will be reset anew, and the HTML will be reset anew also. I hope my problem is enough clear to understand.
I have solved the problem.
I just add a reload function to solve this problem.
backhome.addEventListener('click', () => {
frontpage.classList.add("visibility");
frontpage.classList.remove("hidden");
resultpg.classList.add('hidden')
resultpg.classList.remove('visibility')
//reload function
window.location.reload();
})

JS todo list item checked, and add item

I am aiming to create a JS todo list similar to https://www.w3schools.com/howto/howto_js_todolist.asp
I have created the basic structure of my todo list application and the function of the close buttons.
These are working well, but I have a problem with adding new todo list items and checking and unchecking todo items.
I'm not sure if I'm using the classlist toggle property well, and also cannot figure why the add button doesn't work at all.
var todoitemlist = document.getElementsByClassName('todo-item');
var i;
for (i = 0; i < todoitemlist.length; i++) {
var span = document.createElement("SPAN");
span.innerHTML = "Close";
span.className = "closebutton";
todoitemlist[i].appendChild(span);
}
var close = document.getElementsByClassName("closebutton");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var listitem = this.parentElement;
listitem.style.display = "none";
}
}
var todoitemlistx = document.getElementsByClassName('todo-item');
//checked element
var i;
for (i = 0; i < todoitemlistx.length; i++) {
todoitemlistx[i].onclick = function(ev) {
ev.style.backgroundColor = "red";
ev.classList.toggle("todo-item-checked");
}
}
//add another list item
function add() {
var listitem = document.createElement("LI");
listitem.className = "todo-item";
var text = document.getElementById('todoinput').value;
var myul = getElementById('todo-list');
var t = document.createTextNode(text);
listitem.appendChild(t);
myul.appendChild(listitem);
var span = document.createElement("SPAN");
span.innerHTML = "Close";
span.className = "closebutton";
listitem[i].appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
* {
box-sizing: border-box;
}
body {
text-align: center;
margin: 0;
padding: 0;
background-color: #dbf9fc;
font-family: Arial, Helvetica, sans-serif;
color: rgba(0, 27, 39);
}
#todoinput {
margin: 5px;
padding: 5px;
width: 65%;
}
#add-button {
padding: 5px;
margin: 5px;
width: 5%;
background-color: rgba(0, 27, 39);
color: #dbf9fc;
border: none;
border-radius: 5px;
height: 1fr;
cursor: pointer;
}
#add-button:hover {
background-color: black;
}
#todo-list {
display: inline-block;
margin: 0;
padding: 0;
list-style: none;
width: 70%;
}
.todo-item {
position: relative;
display: flex;
justify-content: flex-start;
background-color: white;
border: 2px solid black;
padding: 5px;
margin: 5px;
}
.closebutton {
cursor: pointer;
justify-self: flex-end;
background-color: #e6772d;
position: absolute;
right: 0;
top: 0;
color: white;
float: right;
padding: 5px;
width: 30%;
margin: 0;
}
.closebutton:hover {
background-color: #c46526;
}
.todo-item-checked {
position: relative;
display: flex;
justify-content: flex-start;
background-color: rgb(187, 187, 187);
border: 2px solid black;
padding: 5px;
margin: 5px;
text-decoration: line-through;
}
.black {
background-color: black;
}
<main class="centered">
<h1>ToDo List JS</h1>
<h3>js project</h3>
<form action="">
<input type="text" name="" id="todoinput" placeholder="Enter the activity you've wented to do">
<input type="button" value="Add" id="add-button" onclick="add()">
</form>
<ul id="todo-list">
<li class="todo-item">
Hit the lights
</li>
<li class="todo-item">
Hit the lights
</li>
<li class="todo-item">
Hit the lights
</li>
<li class="todo-item-checked todo-item">
Hit the lights
</li>
</ul>
</main>
I remember what it was like starting development and how hard it could be, so I persevered with this.
I thought it would be a few small changes but it turned into a massive rewrite.
Una grande padulo, as the Italians like to say.
I hope you can or try to understand what I did here.
The big lesson would be, don't write the same code twice, put it in a separate function.
So this seems to work.
Let me know if it doesn't.
var todoitemlist=document.getElementsByClassName('todo-item');
for(var i=0;i<todoitemlist.length;i++)
{
myawesomeclosebutton(todoitemlist[i]);
todoitemlist[i].addEventListener('click',myawesomebackground);
}
function myawesomeclosebutton(myawesomeitem)
{
var span=document.createElement('span');
span.innerHTML='Close';
span.className='closebutton';
span.addEventListener('click',myawesomecloseevent);
myawesomeitem.appendChild(span);
}
function myawesomebackground(ev)
{
if(ev.target.style.backgroundColor!='red')
{
ev.target.style.backgroundColor='red';
}
else
{
ev.target.style.backgroundColor='transparent';
}
}
function myawesomecloseevent(event)
{
var div=event.target.parentElement;
div.style.display='none';
}
function add()
{
var listitem=document.createElement('li');
listitem.className='todo-item';
var myawesomeinput=document.getElementById('todoinput');
var text=myawesomeinput.value;
var myul=document.getElementById('todo-list');
var t=document.createTextNode(text);
listitem.appendChild(t);
myul.appendChild(listitem);
listitem.addEventListener('click',myawesomebackground);
myawesomeclosebutton(listitem);
myawesomeinput.value='';
}

Function removes items from localStorage only if run manually

I'm looking for advice/tips on how to fix a function that is supposed to remove items from localStorage. I'm following a tutorial by John Smilga that I found on Youtube. Although I've modeled my code on his, apparently, I have missed something.
This function works perfectly well if I run it manually from the console and pass in the id of the item that I want to remove from localStorage.
function removeFromLocalStorage(id) {
console.log(id);
let storageItems = getLocalStorage();
console.log(storageItems);
storageItems = storageItems.filter(function(singleItem) {
if (singleItem.id !== id) {
return singleItem;
}
})
console.log(storageItems);
localStorage.setItem("list", JSON.stringify(storageItems));
}
However, when this function is triggered by the deleteItem() function, it refuses to remove the item from localStorage. It still works, there are a bunch of console.logs in it that track its execution, and I can check that it receives the correct item id as the argument, but for some reason it doesn't filter out the item that needs to be removed. I am completely lost and have no idea how to identify the problem. I can't debug it with console.logs as I usually do. I will be very grateful if you help me find the problem. Any advice will be appreciated.
In case the entire code is needed, please find it below.
const form = document.querySelector(".app__form");
const alert = document.querySelector(".app__alert");
const input = document.querySelector(".app__input");
const submitBtn = document.querySelector(".app__submit-btn");
const itemsContainer = document.querySelector(".app__items-container");
const itemsList = document.querySelector(".app__items-list");
const clearBtn = document.querySelector(".app__clear-btn");
let editElement;
let editFlag = false;
let editId = "";
form.addEventListener("submit", addItem);
clearBtn.addEventListener("click", clearItems);
function addItem(e) {
e.preventDefault();
const id = Math.floor(Math.random() * 9999999999);
if (input.value && !editFlag) {
const item = document.createElement("div");
item.classList.add("app__item");
const attr = document.createAttribute("data-id");
attr.value = id;
item.setAttributeNode(attr);
item.innerHTML = `<p class='app__item-text'>${input.value}</p>
<div class='app__item-btn-cont'>
<button class='app__item-btn app__item-btn--edit'>edit</button>
<button class='app__item-btn app__item-btn--delete'>delete</button>
</div>`
const editBtn = item.querySelector(".app__item-btn--edit");
const deleteBtn = item.querySelector(".app__item-btn--delete");
editBtn.addEventListener("click", editItem);
deleteBtn.addEventListener("click", deleteItem);
itemsList.appendChild(item);
displayAlert("item added", "success");
addToLocalStorage(id, input.value);
setBackToDefault();
itemsContainer.classList.add("app__items-container--visible");
} else if (input.value && editFlag) {
editElement.textContent = input.value;
// edit local storage
editLocalStorage(editId, input.value);
setBackToDefault();
displayAlert("item edited", "success");
} else {
displayAlert("empty field", "warning");
}
}
function setBackToDefault() {
input.value = "";
editFlag = false;
editId = "";
submitBtn.textContent = "Submit";
submitBtn.className = "app__submit-btn";
}
function displayAlert(text, action) {
alert.textContent = text;
alert.classList.add(`app__alert--${action}`);
setTimeout(function() {
alert.textContent = "";
alert.classList.remove(`app__alert--${action}`);
}, 700)
}
function clearItems() {
const items = document.querySelectorAll(".app__item");
if (items.length > 0) {
items.forEach(function(singleItem) {
itemsList.removeChild(singleItem);
})
itemsContainer.classList.remove("app__items-container--visible");
displayAlert("items cleared", "cleared");
setBackToDefault();
}
}
function editItem(e) {
const item = e.currentTarget.parentElement.parentElement;
editElement = e.currentTarget.parentElement.previousElementSibling;
editId = item.dataset.id;
editFlag = true;
input.value = editElement.textContent;
submitBtn.textContent = "Edit";
submitBtn.classList.add("app__submit-btn--edit");
input.focus();
}
function deleteItem(e) {
const item = e.currentTarget.parentElement.parentElement;
const itemId = item.dataset.id;
removeFromLocalStorage(itemId);
displayAlert("item removed", "cleared");
setBackToDefault();
itemsList.removeChild(item);
if (itemsList.children.length === 0) {
itemsContainer.classList.remove("app__items-container--visible");
}
}
function addToLocalStorage(id, value) {
const itemsObj = {id: id, value: input.value};
let storageItems = getLocalStorage();
storageItems.push(itemsObj);
localStorage.setItem("list", JSON.stringify(storageItems));
}
function removeFromLocalStorage(id) {
console.log(id);
let storageItems = getLocalStorage();
console.log(storageItems);
storageItems = storageItems.filter(function(singleItem) {
if (singleItem.id !== id) {
return singleItem;
}
})
console.log(storageItems);
localStorage.setItem("list", JSON.stringify(storageItems));
}
function editLocalStorage(id, value) {
}
function getLocalStorage() {
return localStorage.getItem("list") ? JSON.parse(localStorage.getItem("list")) : [];
}
* {
margin: 0;
padding: 0;
}
.app {
width: 70%;
max-width: 600px;
margin: 75px auto 0;
}
.app__title {
text-align: center;
/* color: #1B5D81; */
margin-top: 20px;
color: #377FB4;
}
.app__alert {
width: 60%;
margin: 0 auto;
text-align: center;
font-size: 20px;
color: #215884;
border-radius: 7px;
height: 23px;
transition: 0.4s;
text-transform: capitalize;
}
.app__alert--warning {
background-color: rgba(243, 117, 66, 0.2);
color: #006699;
}
.app__alert--success {
background-color: rgba(165, 237, 92, 0.4);
color: #3333ff;
}
.app__alert--cleared {
background-color: #a978da;
color: white;
}
.app__input-btn-cont {
display: flex;
margin-top: 30px;
}
.app__input {
width: 80%;
box-sizing: border-box;
font-size: 20px;
padding: 3px 0 3px 10px;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
border-right: none;
border: 1px solid #67B5E2;
background-color: #EDF9FF;
}
.app__input:focus {
outline: transparent;
}
.app__submit-btn {
display: block;
width: 20%;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
border-left: none;
background-color: #67B5E2;
border: 1px solid #67B5E2;
cursor: pointer;
font-size: 20px;
color: white;
transition: background-color 0.7s;
padding: 3px 0;
}
.app__submit-btn--edit {
background-color: #95CB5D;
}
.app__submit-btn:active {
width: 19.9%;
padding: 0 0;
}
.app__submit-btn:hover {
background-color: #377FB4;
}
.app__submit-btn--edit:hover {
background-color: #81AF51;
}
.app__items-container {
visibility: hidden;
/* transition: 0.7s; */
}
.app__items-container--visible {
visibility: visible;
}
.app__item {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.app__item:hover {
background-color: #b9e2fa;
border-radius: 10px;
}
.app__item-text {
padding-left: 10px;
font-size: 20px;
color: #1B5D81;
}
.app__item-btn-cont {
display: flex;
}
.app__item-btn-img {
width: 20px;
height: 20px;
}
.app__item-btn {
border: none;
background-color: transparent;
cursor: pointer;
display: block;
font-size: 18px;
}
.app__item-btn--edit {
margin-right: 45px;
color: #2c800f;
}
.app__item-btn--delete {
margin-right: 15px;
color: rgb(243, 117, 66);
}
.app__clear-btn {
display: block;
width: 150px;
margin: 20px auto;
border: none;
background-color: transparent;
font-size: 20px;
color: rgb(243, 117, 66);
letter-spacing: 2px;
cursor: pointer;
transition: border 0.3s;
border: 1px solid transparent;
}
.app__clear-btn:hover {
border: 1px solid rgb(243, 117, 66);
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" name="viewport" content="width=device-width,
initial-scale=1">
<link rel="stylesheet" href="list.css">
<title>To Do List App</title>
</head>
<body>
<section class="app">
<form class="app__form">
<p class="app__alert"></p>
<h2 class="app__title">To Do List</h2>
<div class="app__input-btn-cont">
<input class="app__input" type="text" id="todo" placeholder="do stuff">
<button class="app__submit-btn">Submit</button>
</div>
</form>
<div class="app__items-container">
<div class="app__items-list">
</div>
<button class="app__clear-btn">Clear Items</button>
</div>
</section>
<script src="list.js"></script>
</body>
</html>
Your code is fine you just used the wrong comparison operator.
In your case you are comparing 2 IDs (operands) to see if they match up, so you should use normal operators such as (==, !=), but instead in your case, you have used strict operators which are used to compare the operand type and the operand itself.
You can learn more about Comparison Operators here.
Ultimatly,
In your function removeFromLocalStorage(id), you have an extra equal sign in your if function.
Instead of:
if (singleItem.id !== id) {
return singleItem;}
It should be:
if (singleItem.id != id) {
return singleItem;}
Hope this helps.

Why isn't the string.length updating?

This is my first piece of code js done on my own. I am trying to have an input field to add items to the list and then if you press the button to generate code it will collect all the checked items and copy the text into another div.
Basically, my question is around two variables:
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
Let say I have 4 items in the list. If I add a new item to the list I can see the list.length add this new item, it changes from 4 to 5.
But it doesn't happen with listCopy.length the value keeps being 4.
Why is it happening if lstCopy is inside of list?
How can I have listCopy updated too?
Here is my code:
const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
const clonedCode = document.querySelector('.code p');
//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {
//Draggable
item.draggable = "true";
item.classList.add("list--item");
//Checkbox
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.name = "chkboxName1";
checkbox.value = "value";
checkbox.id = "id";
item.insertBefore(checkbox, item.childNodes[0] || null);
//Remove button
let remove = document.createElement('button');
remove.className = 'remove';
remove.textContent = 'x';
item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
attachItemListButton(list[i]);
}
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
let copyTextFromList = "";
for (let i = 0; i < listCopy.length; i += 1) {
if (listCopy[i].parentNode.querySelector("input:checked")) {
copyTextFromList += listCopy[i].textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
let li = document.createElement('li');
let span = document.createElement('span');
span.textContent = addItemInput.value;
listUl.appendChild(li);
li.appendChild(span);
attachItemListButton(li);
addItemInput.value = '';
});
//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
if (event.target.tagName == 'BUTTON') {
if (event.target.className == 'remove') {
let li = event.target.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
}
}
});
/* Google fonts */
#import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
/* Root */
:root {
--color-white: #fff;
--color-black: #2D3142;
--color-black-2: #0E1116;
--color-gray: #CEE5F2;
--color-gray-2: #ACCBE1;
--color-gray-3: #CEE5F2;
--color-green: #439775;
--color-blue: #4686CC;
}
body {
font-family: 'Heebo', sans-serif;
font-weight: 400;
font-size: 16px;
color: black;
}
h2 {
font-weight: 700;
font-size: 1.5rem;
}
h3 {
font-weight: 700;
font-size: 1.25rem;
}
button {
background: var(--color-blue);
padding: 5px 10px;
border-radius: 5px;
color: var(--color-white);
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
}
ul.list {
list-style-type: none;
padding: 0;
max-width: 300px;
}
.list button {
background: var(--color-black);
}
.list--item {
display: flex;
justify-content: space-between;
align-items: center;
width: auto;
margin: 5px auto;
padding: 5px;
cursor: move;
background: var(--color-gray);
border-radius: 5px;
}
.list--item.draggingElement {
opacity: 0.4;
}
.list--item.over {
border-top: 3px solid var(--color-green);
}
button.remove {
margin: auto 0 auto auto;
}
input#id {
margin: auto 5px auto 0;
}
.button-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
max-width: 300px;
}
.button-wrapper .addItemInput {
width: 63%;
border-radius: 5px 0 0 5px;
}
.button-wrapper .addItemButton {
width: 35%;
border-radius: 0 5px 5px 0;
}
.button-wrapper .generateCode {
width: 100%;
background: var(--color-green);
margin-top: 5px;
}
.code p {
background: var(--color-gray); padding: 5px;
border: 1px solid var(--color-gray-2);
min-height: 20px;
font-weight: 300;
}
<ul class="list">
<li><span>Header</span></li>
<li><span>Hero</span></li>
<li><span>Intro</span></li>
<li><span>Footer</span></li>
</ul>
<div class="button-wrapper">
<input type="text" class="addItemInput" placeholder="Item description">
<button class="addItemButton">Add item</button>
<button class="generateCode">Generate code</button>
</div>
<div class="code">
<h2>Code</h2>
<p></p>
</div>
There are two variants of NodeList, live and non-live ones. querySelectorAll returns a static NodeList that is not live. .children returns a live one (technically it returns an HTMLCollection but you can ignore this distinction for now).
To make listCopy be live as well, you could use listUl.getElementsByTagName('span')…
To select elements by their classes, use getElementsByClassName. There is no way (that I know of) to get a live collection with CSS or XPath (i.e. more complex) queries, though.
The problem is that const listCopy = listUl.querySelectorAll('span'); is initiated with the span array from the beginning.
In order to get updated list
const listCopy = listUl.querySelectorAll('span'); will be let listCopy = listUl.querySelectorAll('span'); and in your function
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
// add the following line - in this way you will select the span from the updated list
listCopy = listUl.querySelectorAll('span');
let copyTextFromList = "";
for (let i = 0; i < listCopy.length; i += 1) {
if (listCopy[i].parentNode.querySelector("input:checked")) {
copyTextFromList += listCopy[i].textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
if you want to use querySelectorAll, this maybe help. with this every time you check the length it recalculates and returns the value. Symbol.iterator helps you to manipulate for...of loops.
const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = {
get length() {
return listUl.querySelectorAll('span').length
},
*[Symbol.iterator]() {
let i = 0;
const l = listUl.querySelectorAll('span');
while( i < l.length ) {
yield l[i];
i++;
}
}
};
const clonedCode = document.querySelector('.code p');
//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {
//Draggable
item.draggable = "true";
item.classList.add("list--item");
//Checkbox
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.name = "chkboxName1";
checkbox.value = "value";
checkbox.id = "id";
item.insertBefore(checkbox, item.childNodes[0] || null);
//Remove button
let remove = document.createElement('button');
remove.className = 'remove';
remove.textContent = 'x';
item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
attachItemListButton(list[i]);
}
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
let copyTextFromList = "";
for (let item of listCopy) {
if (item.parentNode.querySelector("input:checked")) {
copyTextFromList += item.textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
let li = document.createElement('li');
let span = document.createElement('span');
span.textContent = addItemInput.value;
listUl.appendChild(li);
li.appendChild(span);
attachItemListButton(li);
addItemInput.value = '';
});
//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
if (event.target.tagName == 'BUTTON') {
if (event.target.className == 'remove') {
let li = event.target.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
}
}
});
/* Google fonts */
#import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
/* Root */
:root {
--color-white: #fff;
--color-black: #2D3142;
--color-black-2: #0E1116;
--color-gray: #CEE5F2;
--color-gray-2: #ACCBE1;
--color-gray-3: #CEE5F2;
--color-green: #439775;
--color-blue: #4686CC;
}
body {
font-family: 'Heebo', sans-serif;
font-weight: 400;
font-size: 16px;
color: black;
}
h2 {
font-weight: 700;
font-size: 1.5rem;
}
h3 {
font-weight: 700;
font-size: 1.25rem;
}
button {
background: var(--color-blue);
padding: 5px 10px;
border-radius: 5px;
color: var(--color-white);
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
}
ul.list {
list-style-type: none;
padding: 0;
max-width: 300px;
}
.list button {
background: var(--color-black);
}
.list--item {
display: flex;
justify-content: space-between;
align-items: center;
width: auto;
margin: 5px auto;
padding: 5px;
cursor: move;
background: var(--color-gray);
border-radius: 5px;
}
.list--item.draggingElement {
opacity: 0.4;
}
.list--item.over {
border-top: 3px solid var(--color-green);
}
button.remove {
margin: auto 0 auto auto;
}
input#id {
margin: auto 5px auto 0;
}
.button-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
max-width: 300px;
}
.button-wrapper .addItemInput {
width: 63%;
border-radius: 5px 0 0 5px;
}
.button-wrapper .addItemButton {
width: 35%;
border-radius: 0 5px 5px 0;
}
.button-wrapper .generateCode {
width: 100%;
background: var(--color-green);
margin-top: 5px;
}
.code p {
background: var(--color-gray); padding: 5px;
border: 1px solid var(--color-gray-2);
min-height: 20px;
font-weight: 300;
}
<ul class="list">
<li><span>Header</span></li>
<li><span>Hero</span></li>
<li><span>Intro</span></li>
<li><span>Footer</span></li>
</ul>
<div class="button-wrapper">
<input type="text" class="addItemInput" placeholder="Item description">
<button class="addItemButton">Add item</button>
<button class="generateCode">Generate code</button>
</div>
<div class="code">
<h2>Code</h2>
<p></p>
</div>

Categories

Resources