Is there a fix for number counter bug using vanilla javascript - javascript

I made products quantity counter for e-commerce that should increase and decrease the quantity by 1 and it works only if the elements exist in dom without appending from javascript
but when I click on the get button to append from javascript the last appended element only increases or decreases by one.
here is the code:
class Cart {
static global() {
Cart.getBtn = document.getElementById('get');
Cart.main = document.getElementsByTagName('main')[0];
Cart.min = 1;
}
constructor(num) {
this.num = num;
}
static insertEl() {
const div = document.createElement('div');
div.innerHTML = `
<br>
<div>
<button type="button" class="minus">-</button>
<input type="number" min="1" max="20" value="1">
<button type="button" class="plus">+</button>
</div>
`;
Cart.main.appendChild(div);
}
static plusFunc() {
// plus btn
let plus = document.querySelectorAll('.plus');
plus.forEach(function(btn) {
btn.addEventListener('click', function(e) {
let input = e.target.previousElementSibling;
let max = Number(input.getAttribute('max'));
let num1 = new Cart(Number(input.value));
if (num1.num >= Cart.min) {
num1.num += 1;
}
if (num1.num >= max) {
num1.num = max;
}
input.value = num1.num;
});
});
}
static minusFunc() {
// minus btn
let minus = document.querySelectorAll('.minus');
minus.forEach(function(btn) {
btn.addEventListener('click', function(e) {
let input = e.target.nextElementSibling;
let max = Number(input.getAttribute('max'));
let num1 = new Cart(Number(input.value));
if (num1.num <= max) {
num1.num -= 1;
}
if (num1.num <= Cart.min) {
num1.num = Cart.min;
}
input.value = num1.num;
});
});
}
}
Cart.global();
// events
Cart.getBtn.addEventListener('click', function() {
Cart.insertEl();
Cart.plusFunc();
Cart.minusFunc();
});
<button type="button" id="get">get</button>
<main></main>

You're adding a new plus and a new minus listener to each element whenever a new element is appended. Have plusFunc and minusFunc only add to the newly created element instead:
class Cart {
static global() {
Cart.getBtn = document.getElementById('get');
Cart.main = document.getElementsByTagName('main')[0];
Cart.min = 1;
}
constructor(num) {
this.num = num;
}
static insertEl() {
const div = document.createElement('div');
div.innerHTML = `
<br>
<div>
<button type="button" class="minus">-</button>
<input type="number" min="1" max="20" value="1">
<button type="button" class="plus">+</button>
</div>
`;
Cart.main.appendChild(div);
return div;
}
static plusFunc(btn) {
btn.addEventListener('click', function(e) {
let input = e.target.previousElementSibling;
let max = Number(input.getAttribute('max'));
let num1 = new Cart(Number(input.value));
if (num1.num >= Cart.min) {
num1.num += 1;
}
if (num1.num >= max) {
num1.num = max;
}
input.value = num1.num;
});
}
static minusFunc(btn) {
btn.addEventListener('click', function(e) {
let input = e.target.nextElementSibling;
let max = Number(input.getAttribute('max'));
let num1 = new Cart(Number(input.value));
if (num1.num <= max) {
num1.num -= 1;
}
if (num1.num <= Cart.min) {
num1.num = Cart.min;
}
input.value = num1.num;
});
}
}
Cart.global();
// events
Cart.getBtn.addEventListener('click', function() {
const div = Cart.insertEl();
const [minus, plus] = div.querySelectorAll('button');
Cart.plusFunc(plus);
Cart.minusFunc(minus);
});
<button type="button" id="get">get</button>
<main></main>
But this quite a weird setup - why have a class that basically has nothing but static methods? Consider a plain object instead:
const Cart = {
getBtn: document.getElementById('get'),
main: document.querySelector('main'),
min: 1,
max: 20,
insertEl() {
const div = document.createElement('div');
div.innerHTML = `
<button type="button" class="minus">-</button>
<input type="number" min="1" max="20" value="1">
<button type="button" class="plus">+</button>
`;
this.main.insertAdjacentHTML('beforeend', '<br>');
this.main.appendChild(div);
return div;
}
}
Cart.getBtn.addEventListener('click', function() {
const div = Cart.insertEl();
const [minus, input, plus] = div.children;
minus.addEventListener('click', () => input.value = Math.max(Cart.min, input.value - 1));
plus.addEventListener('click', () => input.value = Math.min(Cart.max, Number(input.value) + 1));
});
<button type="button" id="get">get</button>
<main></main>

Related

Typing in the firt input without focusing

I have an Virtual keyboard with Javascript the keyboard is typing in two inputs after reached maxlength it is focusing to second input. my problem is when i want to type in first input i should clicked to first input to focus it than typing with keyboard numbers
My question is How i can typing using this keyboard without clicking inside input, the first input should start typing immediately after i clicked on the buttons numbers
const maxLength = 7;
const firstInput = document.querySelector("#pin");
const secondInput = document.querySelector("#key");
const changedEvent = new Event("change")
let activeInput;
firstInput.addEventListener("focus", (event) => {
activeInput = event.target;
});
firstInput.addEventListener("change", (event) => {
console.log("i'm changing!");
if (firstInput.value.length >= maxLength) {
activeInput = secondInput;
secondInput.focus();
}
});
secondInput.addEventListener("focus", (event) => {
activeInput = event.target;
});
function resetNumber() {
if (!activeInput) {
console.log("pin");
return;
}
activeInput.value = "";
}
function setNumber(number) {
if (!activeInput) {
console.log("pin");
return;
}
activeInput.value = activeInput.value === number ? "" : (activeInput.value += number);
// manually tell the input that it has changed, so that the event listener defined above gets called. this usually only will happen with actual keyboard input
activeInput.dispatchEvent(changedEvent);
}
<button onclick="resetNumber()">Reset</button>
<button onclick="setNumber(0)">0</button>
<button onclick="setNumber(1)">1</button>
<button onclick="setNumber(2)">2</button>
<button onclick="setNumber(3)">3</button>
<button onclick="setNumber(4)">4</button>
<button onclick="setNumber(5)">5</button>
<button onclick="setNumber(6)">6</button>
<button onclick="setNumber(7)">7</button>
<button onclick="setNumber(8)">8</button>
<button onclick="setNumber(9)">9</button>
<br />
<input type="text" id="pin" />
<input type="text" id="key" />
<button id="reset" onclick="resetNumber()">Reset</button>
<br />
<input type="text" id="pin" />
<input type="text" id="key" />
<script>
const maxLength = 7;
const firstInput = document.querySelector('#pin');
const secondInput = document.querySelector('#key');
const resetBtn = document.querySelector('#reset');
for (let i = 9; i >= 0; i--) {
const numBtn = document.createElement('button');
numBtn.className = 'number';
numBtn.innerText = i;
resetBtn.parentElement.insertBefore(numBtn, resetBtn.nextSibling);
}
const numberBtns = document.querySelectorAll('.number');
const resetNumber = () => {
firstInput.setAttribute('value', '');
secondInput.setAttribute('value', '');
};
const setVal = (e) => {
const num = parseInt(e.target.innerText, 10);
if (firstInput.value.length <= maxLength) return firstInput.setAttribute('value', firstInput.value + num);
secondInput.setAttribute('value', secondInput.value + num);
};
numberBtns.forEach((btn) => btn.addEventListener('click', setVal));
</script>

Cannot set innerHTML on one, of two, identical functions

I have two functions that are essentially identical. The negIndex function works as advertised, no problems, but the posIndex function give me the error "cannot set enterTable.innerHTML to 'null'".
I'm fairly new to Javascript so it could be something obvious, but if it is i'm lost. I've tried a few different things without positive results. Any help would be appreciated.
The HTML
<ul id="exitTable" style="list-style-type: none; display: flex; flex-direction: column; vertical-align: center"></ul>
<br>
<ul id="enterTable" style="list-style-type: none; display: flex; flex-direction: column; vertical-align: center"></ul>
The Javascript
// Put DOM elements into variables
const myForm = document.querySelector('#my-form');
const price = document.querySelector('#stockPrice');
const shares = document.querySelector('#sharesAmount');
const commission = document.querySelector('#commissionAmount');
const fee = document.querySelector('#feeAmount');
const max = document.querySelector('#maxGain');
const msg = document.querySelector('.msg');
const exitTable = document.querySelector('#exitTable');
const enterTable = document.querySelector('#enterTable');
// Listen for form submit
myForm.addEventListener('submit', onSubmit);
function onSubmit(e) {
e.preventDefault();
if (price.value === '' || shares.value === '') {
// alert
msg.classList.add('error');
msg.innerHTML = 'Please enter required fields';
// Remove error after 3 seconds
setTimeout(() => msg.remove(), 3000);
} else {
let subTotal = price.value * shares.value;
subTotal = subTotal.toFixed(2)
let total = subTotal + parseFloat(commission.value);
function popList(name) {
let li = document.createElement('li');
li.textContent = name;
li.style.cssText = 'text-align: center'
return li;
}
//finds the 5%-50% loss amounts based on subTotal
function negIndex(num) {
let negPer = -0.05;
let negArray = [];
let i = 0;
exitTable.innerHTML = "";
while (negPer >= -0.50) {
negArray[i] = parseFloat(num * negPer).toFixed(2);
let s = parseFloat(negPer * 100).toFixed(1) + "% " + negArray[i];
let x = popList(s); //creating list elements
exitTable.appendChild(x);
i++;
negPer += -0.05;
}
}
function posIndex(num) {
let posPer = 0.05;
let posArray = [];
let i = 0;
enterTable.innerHTML = "";
while (posPer <= 1.00) {
posArray[i] = parseFloat(num * posPer).toFixed(2);
let s = parseFloat(posPer * 100).toFixed(1) + "% ->" + posArray[i];
let x = popList(s);
enterTable.appendChild(x);
i++;
posPer += 0.05;
}
}
posIndex(subTotal);
negIndex(subTotal);
}
//Listen for form clear
myForm.addEventListener('reset', onReset);
function onReset() {
price.innerHTML = "";
shares.innerHTML = "";
commission.innerHTML = "";
fee.innerHTML = "";
}
I'm just gessing what your html could look like
// Put DOM elements into variables
const myForm = document.querySelector('#my-form');
const price = document.querySelector('#stockPrice');
const shares = document.querySelector('#sharesAmount');
const commission = document.querySelector('#commissionAmount');
const fee = document.querySelector('#feeAmount');
const max = document.querySelector('#maxGain');
const msg = document.querySelector('.msg');
const exitTable = document.querySelector('#exitTable');
const enterTable = document.querySelector('#enterTable');
let subTotal = 0;
// Listen for form submit
myForm.addEventListener('submit', onSubmit);
function onSubmit(e) {
e.preventDefault();
if (price.value === '' || shares.value === '') {
// alert
msg.classList.add('error');
msg.innerHTML = 'Please enter required fields';
// Remove error after 3 seconds
setTimeout(() => {
msg.classList.remove('error');
msg.innerHTML = '';
}, 3000);
} else {
subTotal = price.value * shares.value;
subTotal = subTotal.toFixed(2)
}
posIndex(subTotal);
negIndex(subTotal);
}
function popList(name) {
let li = document.createElement('li');
li.textContent = name;
li.style.cssText = 'text-align: center'
return li;
}
//finds the 5%-50% loss amounts based on subTotal
function negIndex(num) {
let negPer = -0.05;
let negArray = [];
let i = 0;
exitTable.innerHTML = "";
while (negPer >= -0.50) {
negArray[i] = parseFloat(num * negPer).toFixed(2);
let s = parseFloat(negPer * 100).toFixed(1) + "% " + negArray[i];
let x = popList(s); //creating list elements
exitTable.appendChild(x);
i++;
negPer += -0.05;
}
}
function posIndex(num) {
let posPer = 0.05;
let posArray = [];
let i = 0;
enterTable.innerHTML = "";
while (posPer <= 1.00) {
posArray[i] = parseFloat(num * posPer).toFixed(2);
let s = parseFloat(posPer * 100).toFixed(1) + "% ->" + posArray[i];
let x = popList(s);
enterTable.appendChild(x);
i++;
posPer += 0.05;
}
}
//Listen for form clear
myForm.addEventListener('reset', onReset);
function onReset() {
price.innerHTML = "";
shares.innerHTML = "";
commission.innerHTML = "";
fee.innerHTML = "";
}
<form id="my-form">
<div>
<label for="stockPrice">Stock price</label>
<input type="number" id="stockPrice" />
</div>
<div>
<label for="sharesAmount">Shares amount</label>
<input type="number" id="sharesAmount" />
</div>
<div>
<label for="commissionAmount">Commission amount</label>
<input type="number" id="commissionAmount" />
</div>
<div>
<label for="feeAmount">Fee amount</label>
<input type="number" id="feeAmount" />
</div>
<div>
<label for="maxGain">Max gain</label>
<input type="number" id="maxGain" />
</div>
<div class="msg"></div>
<button type="submit">Submit</button>
</form>
<ul id="exitTable" style="list-style-type: none; display: flex; flex-direction: column; vertical-align: middle"></ul>
<br>
<ul id="enterTable" style="list-style-type: none; display: flex; flex-direction: column; vertical-align: middle"></ul>

Element text not changing when passing selected textContent and new value to an update function

I'm creating a CRUD page where the user can add, delete and edit text, but I have an issue in updating the text after I select it for edit.
In editText function when I click the edit button the text that was added will pop up inside the input field. When I click on the update button (triggering the updateText function), I can see the text in console log but the corresponding html is not updated.
HTML
<div class="main">
<form>
<input type="text" placeholder="search">
</form>
<ul></ul>
<div>
<input class="add-text" type="text" placeholder="Add Text">
<button id="add">Add</button>
<button id="update">update</button>
</div>
</div>
Javascript
const inputsearch = document.querySelector('form input');
const addInputBtn = document.querySelector('#add');
const update = document.querySelector('#update');
addInputBtn.addEventListener('click', addtext);
function addtext(){
let li = document.createElement('li');
let inputadd = document.querySelector('.add-text');
let addedtext = inputadd.value;
let h1Tag = '<h1 id="text">'+addedtext+'</h1>';
let tags = h1Tag + '<button id="delete">Delete</button><button id="edit">Edit</button>';
if(addedtext == ''){
alert('please add some text');
return;
}else{
li.innerHTML = tags;
document.querySelector('ul').appendChild(li);
}
li.querySelectorAll('#delete')[0].addEventListener('click', deleteText);
li.querySelectorAll('#edit')[0].addEventListener('click', editText);
getlist(li, h1Tag);
inputadd.value = '';
}
function deleteText(e) {
e.target.parentNode.remove();
document.querySelector('.add-text').value = '';
}
function editText(e) {
let currentText = e.target.parentNode.firstChild.textContent;
let currentValue = document.querySelector('.add-text');
currentValue.value = currentText;
getupdate(currentText, currentValue);
}
function getupdate(currentText, currentValue) {
update.addEventListener('click', updateText);
function updateText() {
currentText = currentValue.value
console.log(currentText = currentValue.value);
}
}
function getlist(li, h1Tag) {
inputsearch.addEventListener('keyup', serchText);
function serchText(e) {
let typetext = e.target.value.toLowerCase();
if(h1Tag.toLowerCase().indexOf(typetext) != -1){
li.style.display = 'block';
}else{
li.style.display = 'none';
}
}
}
To solve the issue without changing your overall approach, your edit button click needs to get the corresponding element (not just its textContent) and pass it to your getupdate() function to be updated when your update button is clicked. Relatively minor changes to your current functions:
function editText(e) {
const currentText = e.target.parentNode.firstChild;
const currentValue = document.querySelector('.add-text');
currentValue.value = currentText.textContent;
getupdate(currentText, currentValue);
}
function getupdate(currentText, currentValue) {
update.addEventListener('click', updateText);
function updateText() {
currentText.textContent = currentValue.value;
}
}
There are some other issues with your code, particularly the creation of multiple elements with the same id (which is malformed and will likely become problematic as you add additional features). Following is a snippet that addresses that issue as well as simplifying some of your functions and fixing the search.
const search = document.querySelector('form input');
const input = document.querySelector('.add-text');
const container = document.querySelector('ul');
let items = null;
let currentItem = null;
const searchItems = (event) => {
if (items) {
const s = event.currentTarget.value.toLowerCase();
for (const item of items) {
if (item.firstChild.textContent.toLowerCase().indexOf(s) !== -1) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
}
}
};
const deleteItem = (event) => {
currentItem = null;
event.currentTarget.parentNode.remove();
};
const editItem = (event) => {
currentItem = event.currentTarget.parentNode.firstChild;
input.value = currentItem.textContent;
};
const updateItem = () => {
if (currentItem) {
currentItem.textContent = input.value;
}
};
const addItem = () => {
let val = input.value
if (val) {
const li = document.createElement('li');
let inner = '<h1 class="text">' + val + '</h1>';
inner += '<button class="delete">Delete</button>';
inner += '<button class="edit">Edit</button>';
li.innerHTML = inner;
container.appendChild(li);
val = '';
currentItem = li.firstChild;
items = document.querySelectorAll('li');
for (let del of document.querySelectorAll('.delete')) {
del.addEventListener('click', deleteItem);
}
for (let edit of document.querySelectorAll('.edit')) {
edit.addEventListener('click', editItem);
}
} else {
alert('please add some text');
return;
}
};
search.addEventListener('keyup', searchItems);
document.querySelector('#add').addEventListener('click', addItem);
document.querySelector('#update').addEventListener('click', updateItem);
<div class="main">
<form>
<input type="text" placeholder="Search">
</form>
<ul></ul>
<div>
<input class="add-text" type="text" placeholder="Add Text">
<button id="add">Add</button>
<button id="update">Update</button>
</div>
</div>

javascript not adding/removing divs in set order

I'm working with JavaScript and am having issues with a couple of for loops at a specific value.
When the slider value is incremented, the amount of pics increase by one and vice versa for when its lowered. However, for a reason I'm unsure of, it will remove one of the pics when the slider is incremented from 9 to 10, and will add one when it's lowered from 10 to 9. This problem doesn't occur anywhere else in the slider, so I'm not sure whats going on.
Here's the code. The picture used isn't attached but the missing image favicon does the same job.
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
var prevnumb = 0;
var num = 2
var numberofdivs = 0;
output.innerHTML = slider.value;
slider.oninput = function() {
prevnum = num;
output.innerHTML = this.value;
num = this.value;
var newnum = num;
var newprevnum = prevnum;
console.log(prevnum, num);
if (prevnum > num) {
for (newnum; newprevnum > newnum; newnum++) {
var element = document.getElementById("id");
element.parentNode.removeChild(element);
}
} else if (num > prevnum) {
for (newprevnum; newnum > newprevnum; newprevnum++) {
var picpol = document.createElement("img");
picpol.src = "polee.png";
picpol.setAttribute("id", "id");
picpol.setAttribute("class", "polio");
document.getElementById("basecontainer").appendChild(picpol);
console.log(picpol);
}
} else {
console.log("no change");
}
}
body {
text-align: center;
}
#basecustom {
text-align: center;
}
.polio {
margin: none;
padding: none;
}
Base Customization
<br>
<br>
<div id="basecustom">
Select your amount of pics
<input type="range" min="2" max="25" value="2" id="myRange">
<p>Value: <span id="demo"></span></p>
<div id="valcont"></div>
<div id="basecontainer">
<img class="polioo" src="polee.png" id="id"><img class="polioo" src="polee.png" id="id">
</div>
</div>
You were missing casting value to int. By default it is string.
num = parseInt(this.value);
Above casting will fix your problem.
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
var prevnumb = 0;
var num = 2
var numberofdivs = 0;
output.innerHTML = slider.value;
slider.oninput = function() {
prevnum = num;
output.innerHTML = this.value;
num = parseInt(this.value);
var newnum = num;
var newprevnum = prevnum;
console.log(prevnum, num);
if (prevnum > num) {
for (newnum; newprevnum > newnum; newnum++) {
var element = document.getElementById("id");
element.parentNode.removeChild(element);
}
} else if (num > prevnum) {
for (newprevnum; newnum > newprevnum; newprevnum++) {
var picpol = document.createElement("img");
picpol.src = "https://www.vyapin.com/blog/wp-content/uploads/2012/07/bullet_04-1.gif";
picpol.setAttribute("id", "id");
picpol.setAttribute("class", "polio");
document.getElementById("basecontainer").appendChild(picpol);
console.log(picpol);
}
} else {
console.log("no change");
}
}
body {
text-align: center;
}
#basecustom {
text-align: center;
}
.polio {
margin: none;
padding: none;
}
Base Customization
<br>
<br>
<div id="basecustom">
Select your amount of pics
<input type="range" min="2" max="25" value="2" id="myRange">
<p>Value: <span id="demo"></span></p>
<div id="valcont"></div>
<div id="basecontainer">
<img class="polioo" src="https://www.vyapin.com/blog/wp-content/uploads/2012/07/bullet_04-1.gif" id="id"/><img class="polioo" src="https://www.vyapin.com/blog/wp-content/uploads/2012/07/bullet_04-1.gif" id="id"/>
</div>
</div>
change num = this.value; to num = parseInt(this.value,10); in your original code, num will be a string. so when it increments to 10, you will get a string '10'. And prevnum is '9'. And if (prevnum > num) { will be true.

Add or Clear localStorage on button click and show the value in html

I have a code that uses localStorage and javascript. I tried to add more slots, like slot1, slot2, slot3 up to 5. I just copy and paste then change the variable names like like slot1, slot2, slot3 up to 5. But it won't work. Help will be appreciated so much.
Javascript:
var slot = localStorage.getItem("slot");
if (slot == null) {
slot = 10;
}
document.getElementById("slot").innerText = slot;
function reduceSlot() {
if (slot >= 1) {
slot--;
localStorage.setItem("slot", slot);
if (slot > 0) {
document.getElementById('slot').innerText = slot;
} else {
document.getElementById('slot').innerText = "FULL";
document.getElementById("button1").style.display = "none";
}
}
}
document.getElementById("button1").onclick = reduceSlot;
function clearLocalStorage() {
localStorage.clear();
}
HTML:
<p id="slot">10</p>
Deduct
<button onclick="window.localStorage.clear();">Clear All</button>
Fiddle: http://jsfiddle.net/barmar/K8stQ/3/
not sure but. is this what you want to do?? working demo
i changed your code a bit.. you can change it into your liking later..
<span id="slot0">10</span><input type="button" value="Deduct" onclick="(function(){reduceSlot(0)})()" ><br>
<span id="slot1">10</span><input type="button" value="Deduct" onclick="(function(){reduceSlot(1)})()" ><br>
<span id="slot2">10</span><input type="button" value="Deduct" onclick="(function(){reduceSlot(2)})()" ><br>
<span id="slot3">10</span><input type="button" value="Deduct" onclick="(function(){reduceSlot(3)})()" ><br>
<span id="slot4">10</span><input type="button" value="Deduct" onclick="(function(){reduceSlot(4)})()" ><br>
<p>
<button onclick="clearAll()">Clear All</button>
</p>
and for the js...
ls = localStorage.getItem("slots") ;
if(!ls) { localStorage.setItem("slots", "10,10,10,10,10");
}
var slots = localStorage.getItem("slots").split(',').map(Number);
window.onload = updateSlots;
function updateSlots() { for(var i=0;i<slots.length;i++) {
document.getElementById('slot' + i ).innerHTML = slots[i] ;
}}
var reduceSlot = function(slotId) {
console.log(slots[slotId]) ;
if(slots[slotId] >= 1) {
slots[slotId]--; localStorage.setItem("slots",slots);
document.getElementById('slot' + slotId).innerHTML = slots[slotId];
}
else { document.getElementById('slot'+slotId).innerText = "FULL";
}
};
function clearAll() {
window.localStorage.clear();
slots = [10,10,10,10,10];
updateSlots();
}
Try this,
Script
window.ready = function() {
checkStorage();
}
function checkStorage() {
var slot = localStorage.getItem("slot");
if (slot == null) {
slot = 10;
}
document.getElementById("slot").innerHTML = slot;
}
function reduceSlot() {
var slot = localStorage.getItem("slot");
if (slot == null) {
slot = 10;
}
if (slot >= 1) {
slot--;
localStorage.setItem("slot", slot);
if (slot > 0) {
document.getElementById('slot').innerHTML = slot;
} else {
document.getElementById('slot').innerHTML = "FULL";
document.getElementById("button1").style.display = "none";
}
}
}
document.getElementById("button1").onclick = reduceSlot;
document.getElementById("clear").onclick = clear_me;
function clear_me() {
localStorage.clear();
checkStorage();
}
HTML
<p id="slot">10</p>
Deduct
<button id="clear">Clear All</button>
Demo

Categories