I am making a calculator, and creating a new element (the number) every time I press an operator button. I'm wondering how I can get it to where I can infinitely add numbers (1+1+1+1 etc) every time i create the element. I think I'll need to store the current total number somehow, but I can't figure out how to do it. If you need any clarification let me know! Thanks
HTML
<button class="numbers">0</button>
<button class="numbers">1</button>
<button class="numbers">2</button>
<button class="numbers">3</button>
<button class="numbers">4</button>
<button class="numbers">5</button>
<button class="numbers">6</button>
<button class="numbers">7</button>
<button class="numbers">8</button>
<button class="numbers">9</button>
<button id="addition" class="button-operator">+</button>
<button id="equals" class="button-operator">=</button>
<div class="result-container">
<h1 id="value"></h1>
<h1 id="equal"></h1>
</div>
JS
const numbersArray = Array.from(document.querySelectorAll('.numbers'));
const addition = document.getElementById('addition');
const equal = document.getElementById('equal');
const equalSign = document.getElementById('equals');
let newValue = document.createElement('h1');
numbersArray.forEach(element => {
element.addEventListener('click', (e) => {
newValue.innerText = e.target.innerText;
function resultHandler() {
value.innerText = ''
}
addition.addEventListener('click', (e) => {
resultHandler()
})
equalSign.addEventListener('click', (e) => {
equal.innerText = parseInt(newValue.innerText) + parseInt(newValue.innerText);
value.style.display = 'none';
newValue.style.display = 'none';
operator.style.display = 'none';
})
})
})
Related
I am doing an e-commerce project. I am currently trying to create the functionality of the quantity amount for each new added item. However, when the amount of one item altered, though it does not change the other item's quantity, when you try to alter the other item's quantity it starts from the number of the previous item's quantity.
For example, if I make the quantity of 'item1' = 3. Then if I adjust 'item2', whether I increase or decrease, it starts from 3, instead of 1.
I think I am maybe complicating it for myself I am still new to JavaScript.
const quantityIncDec = function (plus, minus) {
let quantity = 1;
plus.forEach(button => {
button.addEventListener('click', function () {
quantity++;
this.parentElement.children[1].textContent = quantity;
});
});
minus.forEach(button => {
button.addEventListener('click', function () {
if (quantity > 1) {
quantity--;
this.parentElement.children[1].textContent = quantity;
}
});
});
};
// Add to Cart Preview
btnAddCart.forEach(element => {
element.addEventListener('click', function () {
const markup = `
<li class="index-preview-list-item">
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
<div class="quantity">
<button class="btn btn-plus">
<i class="fa-solid fa-plus"></i>
</button>
<p class="quantity-value">1</p>
<button class="btn btn-minus">
<i class="fa-solid fa-minus"></i>
</button>
</div>
</div>
<button class="btn btn-delete">
<i class="fa-solid fa-trash-can"></i>
</button>
</li>
`;
clearPreviewText(previewTextCart);
cartPreviewContainer.insertAdjacentHTML('beforeend', markup);
const btnPlus = document.querySelectorAll('.btn-plus');
const btnMinus = document.querySelectorAll('.btn-minus');
quantityIncDec(btnPlus, btnMinus);
const btnDelete = document.querySelectorAll('.btn-delete');
deleteItem(btnDelete);
});
});
The let keyword is used to create a block-scoped variable. So, you will have a single instance of that variable in its block. Let's illustrate this in two examples:
let quantity = 0;
for (let button of document.querySelectorAll(".btn")) {
button.addEventListener("click", function() {
alert(++quantity);
});
}
<input class="btn" type="button" value="1">
<input class="btn" type="button" value="2">
<input class="btn" type="button" value="3">
<input class="btn" type="button" value="4">
<input class="btn" type="button" value="5">
<input class="btn" type="button" value="6">
<input class="btn" type="button" value="7">
As you can see, the counter is being updated whenever you click on a button and it does not separately keep track of each button's quantity. This is your mistake. Now, let's see a corrected example, where quantity is created in the correct block:
for (let button of document.querySelectorAll(".btn")) {
let quantity = 0;
button.addEventListener("click", function() {
alert(++quantity);
});
}
<input class="btn" type="button" value="1">
<input class="btn" type="button" value="2">
<input class="btn" type="button" value="3">
<input class="btn" type="button" value="4">
<input class="btn" type="button" value="5">
<input class="btn" type="button" value="6">
<input class="btn" type="button" value="7">
If you click on different buttons here, then you will see that each is having "its own" quantity. So, having said this, let's apply a similar fix for your code:
const quantityIncDec = function (plus, minus) {
//quantity is no longer defined here, because then it's out of the loop's
//block and its value will be shared between the buttons
plus.forEach(button => {
//Instead, we create quantity here and it will be therefore in the
//context of the "current" button
let quantity = 1;
button.addEventListener('click', function () {
quantity++;
this.parentElement.children[1].textContent = quantity;
});
});
minus.forEach(button => {
button.addEventListener('click', function () {
if (quantity > 1) {
quantity--;
this.parentElement.children[1].textContent = quantity;
}
});
});
};
// Add to Cart Preview
btnAddCart.forEach(element => {
element.addEventListener('click', function () {
const markup = `
<li class="index-preview-list-item">
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
<div class="quantity">
<button class="btn btn-plus">
<i class="fa-solid fa-plus"></i>
</button>
<p class="quantity-value">1</p>
<button class="btn btn-minus">
<i class="fa-solid fa-minus"></i>
</button>
</div>
</div>
<button class="btn btn-delete">
<i class="fa-solid fa-trash-can"></i>
</button>
</li>
`;
clearPreviewText(previewTextCart);
cartPreviewContainer.insertAdjacentHTML('beforeend', markup);
const btnPlus = document.querySelectorAll('.btn-plus');
const btnMinus = document.querySelectorAll('.btn-minus');
quantityIncDec(btnPlus, btnMinus);
const btnDelete = document.querySelectorAll('.btn-delete');
deleteItem(btnDelete);
});
});
EDIT
The solution above was ignoring that a minus button also has to work with the same quantity, so I apply a fix for it:
const quantityIncDec = function (plus, minus) {
//quantity is no longer defined here, because then it's out of the loop's
//block and its value will be shared between the buttons
let limit = Math.max(plus.length, minus.length);
for (index = 0; index < limit; index++) {
if (plus.length > index) {
let plusButton = plus[index];
plusButton.addEventListener('click', function () {
quantity++;
this.parentElement.children[1].textContent = quantity;
});
}
if (minus.length > index) {
let minusButton = minus[index];
minusButton.addEventListener('click', function () {
if (quantity > 1) {
quantity--;
this.parentElement.children[1].textContent = quantity;
}
});
}
}
};
// Add to Cart Preview
btnAddCart.forEach(element => {
element.addEventListener('click', function () {
const markup = `
<li class="index-preview-list-item">
<img src="${this.parentElement.children[0].src}" alt="" />
<div>
<h4 class="product-name">${this.parentElement.children[1].textContent}</h4>
<div class="quantity">
<button class="btn btn-plus">
<i class="fa-solid fa-plus"></i>
</button>
<p class="quantity-value">1</p>
<button class="btn btn-minus">
<i class="fa-solid fa-minus"></i>
</button>
</div>
</div>
<button class="btn btn-delete">
<i class="fa-solid fa-trash-can"></i>
</button>
</li>
`;
clearPreviewText(previewTextCart);
cartPreviewContainer.insertAdjacentHTML('beforeend', markup);
const btnPlus = document.querySelectorAll('.btn-plus');
const btnMinus = document.querySelectorAll('.btn-minus');
quantityIncDec(btnPlus, btnMinus);
const btnDelete = document.querySelectorAll('.btn-delete');
deleteItem(btnDelete);
});
});
I'm not sure, If I understood your question correctly. The problem in your source code is, that the only single quantity variable you are using for all of your products. But each product has it's own quantity state, therefore In your case, If you will modify quantity of one product, you will also modify initial quantity state of all another products.
Inside listener callback method, you must firstly get the previous quantity state for the current product and after that increment that value. Also another way is for example save current product quantities into array variable, and then you will need firstly find the initial quantity state from right array value, then increment and then save back modified value to that array.
// ...or ungly but most simple solution, take text content, convert to Int, then increment and store back to the element
this.parentElement.children[1].textContent = parseInt(this.parentElement.children[1].textContent)+1;
Edited answer:
// Write Javascript code!
const appDiv = document.getElementById('app');
appDiv.innerHTML = `<div id="basket">Basket</div>`;
let items = [
{
id: 24,
name: 'halabala',
qty: 10,
},
];
function Basket() {
const render = () => {
const elBasket = document.getElementById('basket');
elBasket.innerHTML = ''; // Remove all childs from previous render
// console.log(elBasket);
if (items.length) {
items.forEach((item) => {
const that = this;
const elDiv = document.createElement('div');
const elSpan = document.createElement('span');
elSpan.innerText = ' ' + item.name + ' (' + item.qty + ')';
const btnPlus = document.createElement('button');
btnPlus.innerText = '+';
btnPlus.addEventListener('click', (event) => {
event.preventDefault();
Basket().incrementItem(item.id);
});
const btnMinus = document.createElement('button');
btnMinus.innerText = '-';
btnMinus.addEventListener('click', (event) => {
event.preventDefault();
Basket().decrementItem(item.id);
});
elDiv.appendChild(btnPlus);
elDiv.appendChild(btnMinus);
elDiv.appendChild(elSpan);
elBasket.appendChild(elDiv);
});
}
};
return {
init: () => {
render();
},
addItem: (itemId, itemName, gty = 1) => {
items.push({ id: itemId, name: itemName, qty: qty });
render();
},
removeItem: (itemId) => {
items = items.filter((i) => i.id != itemId);
render();
},
incrementItem: (itemId) => {
const item = items.find((i) => i.id === itemId);
if (!item)
throw new Error('Unable to increment, because item not found!');
item.qty++;
render();
},
decrementItem: (itemId) => {
const item = items.find((i) => i.id === itemId);
if (!item)
throw new Error('Unable to decrement, because item not found!');
item.qty--;
render();
},
clearBasket: () => {
items = [];
},
};
}
Basket().init();
Good day! I've been trying to figure out how to create a delete function in my todo app. I dont know what to do next and the delete function as well as the eventListener is not correct. I hope you guys can help me. I want to fully understand every small projects that I make. Thank you in advance! :)
const inputBox = document.querySelector('.input')
const addBtn = document.querySelector('.input-button')
const todoMain = document.querySelector('.todo-list')
const deleteBtn = document.querySelector('.delete-button')
const deleteAllBtn = document.querySelector('.clear-all')
//Event listeners
inputBox.addEventListener("keyup", function(){
let userInput = inputBox.value;
if (userInput.trim() != 0) {
addBtn.classList.add("active")
} else {
addBtn.classList.remove("active");
}
})
addBtn.addEventListener("click", todoAdd);
todoMain.addEventListener("click", todoDelete);
// Functions
function todoAdd(event){
event.preventDefault();
const todoLi = document.createElement('li');
todoLi.innerText = inputBox.value;
const todoDeleteBtn = document.createElement('button');
todoDeleteBtn.innerHTML = `<i class="fas fa-trash-alt"></i>`;
todoDeleteBtn.classList.add('delete-button')
todoLi.appendChild(todoDeleteBtn);
todoMain.appendChild(todoLi);
inputBox.value = '';
addBtn.classList.remove("active");
};
function todoDelete(e){
const item = e.target;
if (item.classList[0] === 'delete-button'){
todoMain.removeChild(todoLi);
}
}
<link crossorigin rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<div class="container">
<h1>TODO list</h1>
<div class="input-container">
<input type="text" class="input" placeholder="Input Text Here">
<button class="input-button"><i class="fas fa-plus"></i></button>
</div>
<ul class="todo-list">
</ul>
<div class="footer">
<span>You have<span class="pending">0</span>pending task left</span>
<button class="clear-all">Clear All</button>
</div>
</div>
I have implemented it quite simply as an example.
When creating the ToDo item, I add a key for the text and a data attribute for the delete button and an onclick event.
The key is important to have the relation between button and text. First i used new Date() but i updated with an random Method. (Math.random()+1).toString().split('.')[1];
For deletAll() you can get the entire Parent Node and set html to an empty string.
const inputBox = document.querySelector('.input')
const addBtn = document.querySelector('.input-button')
const todoMain = document.querySelector('.todo-list')
const deleteBtn = document.querySelector('.delete-button')
const deleteAllBtn = document.querySelector('.clear-all')
//Event listeners
inputBox.addEventListener("keyup", function(){
let userInput = inputBox.value;
if (userInput.trim() != 0) {
addBtn.classList.add("active")
} else {
addBtn.classList.remove("active");
}
})
addBtn.addEventListener("click", todoAdd);
todoMain.addEventListener("click", todoDelete);
// Functions
function todoAdd(event){
event.preventDefault();
const todoLi = document.createElement('li');
const key =(Math.random()+1).toString().split('.')[1];
todoLi.innerText = inputBox.value;
todoLi.setAttribute("id", key);
const todoDeleteBtn = document.createElement('button');
todoDeleteBtn.innerHTML = `<i class="fas fa-trash-alt"></i>`;
todoDeleteBtn.classList.add('delete-button')
todoDeleteBtn.onclick = function() {
const _key = this.getAttribute('data-key')
document.getElementById(_key).remove();
this.remove()
}
todoDeleteBtn.setAttribute("data-key", key);
todoLi.appendChild(todoDeleteBtn);
todoMain.appendChild(todoLi);
inputBox.value = '';
addBtn.classList.remove("active");
};
function todoDelete(e){
const item = e.target;
if (item.classList[0] === 'delete-button'){
todoMain.removeChild(todoLi);
}
}
<link crossorigin rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />
<div class="container">
<h1>TODO list</h1>
<div class="input-container">
<input type="text" class="input" placeholder="Input Text Here">
<button class="input-button"><i class="fas fa-plus"></i></button>
</div>
<ul class="todo-list">
</ul>
<div class="footer">
<span>You have<span class="pending">0</span>pending task left</span>
<button class="clear-all">Clear All</button>
</div>
</div>
There are a couple of issues that might be stopping this from working:
Your function todoDelete tries to access the variable todoLi, which doesn't exist in its scope. You define this inside todoAdd, but its scope is limited so you can't access the variable from outside the function.
I suspect what you might want to be doing is passing item instead.
You attach the event listener that triggers todoDelete to your todoMain element, which means that e.target for the function will always be the ul element, not your list element. Your if is then always false so the code never runs.
To fix this, attach the event listener to the todoDeleteBtn in your todoAdd function instead.
I am trying to display the value of the button, but nothing shows up in the console when I press the buttons.
I am missing something and I can't figure it out.
const allButtons = document.querySelector("[data-buttons]");
Array.from(allButtons).forEach(button => {
button.addEventListener("click", () => {
let userPick = button.getAttribute("[data-pick]");
console.log(userPick);
});
});
Thank you! :)
You can directly loop over the Nodelist returned by querySelectorAll
document.querySelectorAll("[data-buttons]").forEach(button => {
button.addEventListener("click", () => {
let userPick = button.getAttribute("data-pick");
console.log(userPick);
});
});
<button data-buttons="1" data-pick="1"> 1</button>
<button data-buttons="2" data-pick="2"> 2</button>
<button data-buttons="3" data-pick="3"> 3</button>
If You have more then one button you need to use querySelectorAll
const allButtons = document.querySelectorAll("[data-buttons]");
Array.from(allButtons).forEach(button => {
button.addEventListener("click", () => {
let userPick = button.getAttribute("data-pick");
console.log(userPick);
});
});
<button data-buttons="1" data-pick="1"> 1</button>
<button data-buttons="2" data-pick="2"> 2</button>
<button data-buttons="3" data-pick="3"> 3</button>
you need to use dataset object in order to read data- related attributes, like this
const allButtons = document.querySelectorAll("[data-buttons]");
Array.from(allButtons).forEach(button => {
button.addEventListener("click", () => {
let userPick = button.dataset.pick;
console.log(userPick);
});
});
Please take a look at the following commented code:
// USE "querySelectorAll" INSTEAD OF "querySelector" TO ACTUALLY GET AN ARRAY-LIKE (NodeList) RESULT.
const allButtons = document.querySelectorAll("[data-buttons]");
// YOU CAN DIRECTLY USE "forEach" ON A NodeList INSTANCE.
allButtons.forEach(button => {
button.addEventListener("click", ({target}) => {
// "getAttribute" NEEDS ATTRIBUTE NAME AS INPUT WITHOUT "[]".
// YOU CAN USE "e.target" INSTEAD OF "button" HERE.
const userPick = target.getAttribute("data-pick");
console.log(userPick);
});
});
<button data-buttons data-pick="A">Button A</button>
<button data-buttons data-pick="B">Button B</button>
<button data-buttons data-pick="C">Button C</button>
<button data-buttons data-pick="D">Button D</button>
<button data-buttons data-pick="E">Button E</button>
I'm a beginner and I wanted to start building projects and I want to determine the number of rounds using the value of the button the user clicks on.
`<div class="game-type">
<h2>GAME TYPE</h2>
<p>choose the number of rounds you'd like to play</p>
<div class="options">
<button value="1" type="button">BEST OF 1</button>
<button value="3" type="button">BEST OF 3</button>
<button value="5" type="button">BEST OF 5</button>
<button value="1000" type="button">FREE MODE</button>
</div>
</div>
`
using JavaScript I tried retrieving the value with "this" for the button that is clicked but it doesn't return anything at all. I want to use the value to set the RoundLimit value equal to the button pressed and end the game when RoundCount is equal to the round limit.
`const rpsGame = () => {
let playerScore = 0;
let computerScore = 0;
let roundCount = 0;
let roundLimit = 0;
// Universal value
const gameType = document.querySelector(".game-type");
//pick number of rounds to play
const roundNum = () => {
const roundSelector = document.querySelectorAll(".game-type buttons");
roundSelector.forEach(roundSelector => {
roundSelector.addEventListener("click", function () {
console.log(this);
});
});
};
roundNum();`
Im a beginner any criticism is appreciated. Thank you!
it's button instead of buttons
const roundNum = () => {
const roundSelector = document.querySelectorAll(".game-type button");
roundSelector.forEach(roundSelector => {
roundSelector.addEventListener("click", function () {
console.log(this);
});
});
};
roundNum();
and to get the value
const roundNum = () => {
const roundSelector = document.querySelectorAll(".game-type button");
roundSelector.forEach(roundSelector => {
roundSelector.addEventListener("click", function (e) {
console.log(e.target.value);
});
});
};
roundNum();
Here is my buttons with different values.
<div id="RAM_BtnGroup" class="btn-group" role="group" aria-label="Basic example" name='ram'>
<button type="button" value="8GB" class="btn btn-outline-success">8GB </button>
<button type="button" value="16GB" class="btn btn-outline-success">16GB </button>
<button type="button" value="32GB" class="btn btn-outline-success">32GB </button>
<button type="button" value="64GB" class="btn btn-outline-success">64GB </button>
Price: <span id="totalCost"></span>
So when I randomly click on different buttons, I'm still getting back the value of 8GB.
var ram = document.querySelector("button[type=button]");
ram.addEventListener('click', calculateTotal)
So how should I click on different buttons in order to get different values?
Should I get the value of button regards to something like this? But it is not working in this way.
var ram = document.querySelector("button[value=8GB][value=16GB][value=32GB][value=64GB]");
million thanks to the suggested solution, it's good enough but my calculateTotal function still not counting on the ram.Can you guide me how to fix this out. Here is my code. I am pretty sure that unitcost, additional and qty run smoothly, but after added in ramcost to get the value of ram, it seem to not returning any total price of all items.
var ram = document.querySelectorAll('button[type="button"]');
ram.forEach((ramm) => {
ramm.addEventListener('click', calculateTotal)
});
var ram_price = {};
ram_price['8GB'] = 200;
ram_price['16GB'] = 300;
ram_price['32GB'] = 400;
ram_price['64GB'] = 500;
function calculateTotal
() {
var ramcost = ram_price[ramm.value];
var unitCost = product_price[productEl.value];
var additionalCost = size_price[sizeEl.value] || 0;
var qty = quantityEl.value || 0;
totalCostEl.textContent = `Total cost: $${(unitCost + additionalCost + ramcost) * qty}`;
}
Can you please check this difference,
queryselector_class:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_document_queryselector_class
as well as
queryselectorall_class:
https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_document_queryselectorall_class
I think it will help.
You have to attach the click event to every button. querySelector() returns only the first matching element, while querySelectorAll() returns all matching elements. That's why you need to use the latter:
var ram = document.querySelectorAll("button[type=button]");
ram.forEach((r) => {
r.addEventListener('click', calculateTotal)
});
function calculateTotal(e) {
console.log(e.target.value);
}
<button type="button" value="8GB" class="btn btn-outline-success">8GB </button>
<button type="button" value="16GB" class="btn btn-outline-success">16GB </button>
<button type="button" value="32GB" class="btn btn-outline-success">32GB </button>
<button type="button" value="64GB" class="btn btn-outline-success">64GB </button>
<div id='container'></div>
I hope this helps, you can create a class ButtonToPress and then instance buttons. Its working
class ButtonToPress {
constructor(n) {
this.n = n;
const button = document.createElement('button');
button.onclick = this.print.bind(this);
button.innerText = this.n
document.getElementById('container').appendChild(button);
}
print() {
console.log(this.n);
}
}
let buttons = [];
for (let i = 8; i < 128; i *= 2) {
buttons[i] = new ButtonToPress(i + 'GB');
console.log(buttons[i]);
}