Plus and Minus Algorithm not working (JavaScript) - javascript

I have two buttons labeled plus and minus side by side and a display box at the center. I have a fixed value box at the top (say 10). When a user clicks plus the display box becomes one while the fixed value reduced to 9 and if I click the minus button, the fixed value returns to 10 while the display value becomes 0... It continues like that until the fixed value is exhausted. The functionality should work for all my four inputs. Below is what have tried.
var minusBtn = document.querySelectorAll("#minus");
var plusBtn = document.querySelectorAll("plus");
var displayvalue = document.querySelectorAll("displayvalue");
var number = 0;
var min = 0;
var fixed = 10;
plusBtn.onclick = function() {
if (fixed > number) {
number = number++;
numberPlace.innerText = number; /// Display the value in place of the number
}
if (number == max) {
} else {
}
}
<body>
<div class="Fixed_number">10</div>
<form>
<label for=""> One
<div id="">
<button id="plus">+</button>
<span id="displayvalue">0</span>
<button id="minus">-</button>
</div>
</label>
</form>
<form>
<label for=""> Two
<div id="">
<button id="plus">+</button>
<span id="displayvalue">0</span>
<button id="minus">-</button>
</div>
</label>
</form>
<form>
<label for=""> Three
<div id="">
<button id="plus">+</button>
<span id="displayvalue">0</span>
<button id="minus">-</button>
</div>
</label>
</form>
<form>
<label for=""> Four
<div id="">
<button id="plus">+</button>
<span id="displayvalue">0</span>
<button id="minus">-</button>
</div>
</label>
</form>
<link rel="stylesheet" href="app.js">
</body>

If you must do it like this than change JS to
var total = document.querySelector(".Fixed_number");
var minusBtn = document.querySelectorAll("#minus");
var plusBtn = document.querySelectorAll("#plus");
plusBtn.forEach(function(item){
item.onclick = function(){
if( parseInt(total.innerText) > 0 ){
item.nextElementSibling.innerText = parseInt(item.nextElementSibling.innerText) + 1;
total.innerText = parseInt(total.innerText) - 1;
}
};
});
minusBtn.forEach(function(item){
item.onclick = function(){
if( parseInt(item.previousElementSibling.innerText) > 0 ){
item.previousElementSibling.innerText = parseInt(item.previousElementSibling.innerText) - 1;
total.innerText = parseInt(total.innerText) + 1;
}
};
});
And you must put type="button" for all buttons or else it will submit the form and reload the page.

Related

Pressing arrow keys affects the result of a function that takes input values

I have a function that takes an input value and sums it into a variable which is then shown in a span element everytime the "keyup" event is triggered. e.g. I press 1 in my input and the span shows 1 as well. I want this span to only work with numbers. The problem is: if I press any of the arrow keys, this span bugs and sums to itself whatever the value the input had previously. e.g. I press 3 and the span shows it as well, but if I press the left arrow key, the span shows 6, I press right arrow key and now it shows 9, etc.
var inputsSum = 0;
let userQuantity = 0;
let totalPrice = document.getElementById("test2");
function calculatePrice() {
const superChosen = document.getElementById("test");
superChosen.addEventListener("keyup",evnt=>{
if(evnt.target.matches("input.q-tints")) {
userQuantity = parseInt(evnt.target.value);
if (userQuantity >= 0) inputsSum += userQuantity;
else if (isNaN(userQuantity)) inputsSum = 0; //Prevents actions from the backspace key
}
totalPrice.innerHTML = `${inputsSum},00`;
})
}
calculatePrice();
<div class="super-chosen-color">
<div class="chosen-color">
<p class="text-chosen">No color chosen</p>
<div class="info-chosen">
<input type="text" name="" id="test" placeholder="0" class="q-tints" autocomplete="off">
<i class="far fa-times-circle"></i>
</div>
</div>
</div>
<div class="total-value">
Total
<span>$</span>
<span class="p-total" id="test2">
0,00
</span>
</div>
Listen for the input event instead of the keyup event.
The input event fires when the value of an <input>, <select>, or <textarea> element has been changed.MDN
var inputsSum = 0;
var totalPrice = document.querySelector('.p-total');
const superChosen = document.querySelector('input');
function calculatePrice() {
superChosen.addEventListener("input",evnt=>{
if(evnt.target.matches("input.q-tints")) {
userQuantity = parseInt(evnt.target.value);
if (userQuantity >= 0) inputsSum += userQuantity;
else if (isNaN(userQuantity)) inputsSum = 0; //Prevents actions from the backspace key
}
totalPrice.innerHTML = `${inputsSum},00`;
})
}
calculatePrice();
<div class="super-chosen-color">
<div class="chosen-color">
<p class="text-chosen">No color chosen</p>
<div class="info-chosen">
<input type="text" name="" id="" placeholder="0" class="q-tints" autocomplete="off">
<i class="far fa-times-circle"></i>
</div>
</div>
</div>
<div class="total-value">
Total
<span>$</span>
<span class="p-total">
0,00
</span>
</div>

A question about usage of cloneNode and insertBefore

I am trying to learn some javascript in web programming. Starting with a simple school registration webpage: the webpage allows to dynamically create any number of grades by clicking "Grade+" button; under each grade, any number of students can be created by clicking "Student+" button. "Grade+" button works as expected, however clicking "Student+" button does not present the student information, not sure what is happening. Any help will be highly appreciated. Thanks in advance.
The reference codes:
<!DOCTYPE html>
<html>
<body>
<div>
<label>Registration</label>
<div class="form-inline justify-content-center" id="school" style="display:none">
<label for="fname">Grade:</label>
<input type="text" id="grade" name="Grade"><br><br>
<div id="students">
<div id="student">
<label for="fname">First:</label>
<input type="text" id="first" name="First"><br><br>
<label for="lname">Last:</label>
<input type="text" id="last" name="Last"><br><br>
</div>
<div class="text-center" id="add_student">
<span id="idStudentRootCopy">----S----</span>
<button type="button" onclick="addItem('student', 'idGradeRootCopy', false)">Student+</button>
</div>
</div>
</div>
<div class="text-center" id="add_grade">
<span id="idGradeRootCopy">----G----</span>
<button type="button" onclick="addItem('school', 'idGradeRootCopy', true)">Grade+</button>
</div>
</div>
<script>
var count = 0;
function addItem(id, index, root) {
var original = document.getElementById(id);
var before = document.getElementById(index);
var clone = original.cloneNode(true);
clone.style.display='block';
clone.id = id + ++count;
var newFields = clone.childNodes;
for (var i = 0; i < newFields.length; i++) {
var fieldName = newFields[i].name;
if (fieldName)
newFields[i].name = fieldName + count;
}
if (root) {
original.parentNode.insertBefore(clone, before.parentNode);
} else {
original.insertBefore(clone, before);
}
}
</script>
</body>
</html>
If you open up the developer tools of your browsers and click the Student+ button you'll get an error message like:
Uncaught DOMException: Node.insertBefore: Child to insert before is
not a child of this node
So you're actually trying to put the cloned node into the wrong spot. Either way things are a bit confusing. Let's say you have clicked the Grade+ button three times and now you decide to click on Student+ of the first clone - how should it know where to put the student as there are three grades?
Well there's a fix of course. Each Student+ button is a child of an unique clone of the school <div> which you also gave an unique id yet (school1, school2,...). So if you pass the addItem() function a reference to the button you actually clicked, we can get it's parent div like:
clickedElement.parentNode.parentNode.parentNode
and add the cloned node using appendChild() instead of insertBefore().
Here's an example (just click on 'Run code snippet'):
var count = 0;
function addItem(id, index, root, clickedElement) {
var original = document.getElementById(id);
var before = document.getElementById(index);
var clone = original.cloneNode(true);
clone.style.display = 'block';
clone.id = id + ++count;
var newFields = clone.childNodes;
for (var i = 0; i < newFields.length; i++) {
var fieldName = newFields[i].name;
if (fieldName)
newFields[i].name = fieldName + count;
}
if (root) {
original.parentNode.insertBefore(clone, before.parentNode);
} else {
clickedElement.parentNode.parentNode.parentNode.appendChild(clone);
}
}
<div>
<label>Registration</label>
<div class="form-inline justify-content-center" id="school" style="display:none">
<label for="fname">Grade:</label>
<input type="text" id="grade" name="Grade"><br><br>
<div id="students">
<div id="student">
<label for="fname">First:</label>
<input type="text" id="first" name="First"><br><br>
<label for="lname">Last:</label>
<input type="text" id="last" name="Last"><br><br>
</div>
<div class="text-center" id="add_student">
<span id="idStudentRootCopy">----S----</span>
<button type="button" onclick="addItem('student', 'idGradeRootCopy', false,this)">Student+</button>
</div>
</div>
</div>
<div class="text-center" id="add_grade">
<span id="idGradeRootCopy">----G----</span>
<button type="button" onclick="addItem('school', 'idGradeRootCopy', true,this)">Grade+</button>
</div>
</div>
Update
If you click on the Grade+ button, it will automatically also 'create' a student input field as it's div is part of the school div. So move it out of the school div and change it's display mode to none.
If you want the new student input field to appear right before the Student+ button, we indeed need to use .insertBefore().
Here's the modified example:
var count = 0;
function addItem(id, index, root, clickedElement) {
var original = document.getElementById(id);
var before = document.getElementById(index);
var clone = original.cloneNode(true);
clone.style.display = 'block';
clone.id = id + ++count;
var newFields = clone.childNodes;
for (var i = 0; i < newFields.length; i++) {
var fieldName = newFields[i].name;
if (fieldName)
newFields[i].name = fieldName + count;
}
if (root) {
original.parentNode.insertBefore(clone, before.parentNode);
} else {
clickedElement.parentNode.insertBefore(clone, clickedElement);
}
}
<div>
<label>Registration</label>
<div id="student" style="display:none">
<label for="fname">First:</label>
<input type="text" id="first" name="First"><br><br>
<label for="lname">Last:</label>
<input type="text" id="last" name="Last"><br><br>
</div>
<div class="form-inline justify-content-center" id="school" style="display:none">
<label for="fname">Grade:</label>
<input type="text" id="grade" name="Grade"><br><br>
<div id="students">
<div class="text-center" id="add_student">
<span id="idStudentRootCopy">----S----</span>
<button type="button" onclick="addItem('student', 'idStudentRootCopy', false,this)">Student+</button>
</div>
</div>
</div>
<div class="text-center" id="add_grade">
<span id="idGradeRootCopy">----G----</span>
<button type="button" onclick="addItem('school', 'idGradeRootCopy', true,this)">Grade+</button>
</div>
</div>

Multi-page form: how do I repeat one page indefinitely by request? HTML, CSS, JS

I am creating a multi-page form (by which I mean on certain button clicks, specific elements change between hidden and visible) following this page's setup. I have 2 pages: 1. add animal and 2. add another animal. I would like to be able to repeat page 2 as many times as the user clicks the button add another animal before they click submit, and store all the inputted animal names to be sent to a python function (so every time a user types in a name on the add another animal page, the previous animal's name isn't overwritten.
My HTML, CSS, and JS are below.
<div class="section-25">
<div class="container-5 w-container">
<div class="text-block-6">Select the level of algorithm you're looking to make</div>
<div class="w-form">
<form id="wf-form-Email-Form" name="wf-form-Email-Form" data-name="Email Form" method="post" action="/add_animal">
<!-- PAGE 1 -->
<div id="page1" class="page">
<!-- 1ST ANIMAL NAME -->
<label for="Enter-species" class="custom-question enter-species" id="one_name">What animal are you interested in?</label>
<input type="text" class="text-field w-input" maxlength="256" name="species" placeholder="Enter name of animal" id="Enter-species" required="">
<p><input type="button" id="C1" value="Add another animal" onClick="showLayer('page2')"></p>
</div>
<!-- PAGE 2 -->
<div id="page2" class="page">
<!-- NEXT ANIMAL NAME -->
<label for="Enter-species" class="custom-question enter-species" id="one_name">What other animal are you interested in?</label>
<input type="text" class="text-field w-input" maxlength="256" name="another_species" placeholder="Enter name of animal" id="Enter-species">
<p><input type="button" id="B1" value="Go Back" onClick="showLayer('page1')">
<input type="button" id="C2" value="Add another animal" onClick="showLayer('page2')">
<input type="button" id="S1" value="Submit" action="/add_animal" </p>
</div>
</form>
</div>
</div>
</div>
CSS:
<!-- CSS -->
<style>
.page {
position: absolute;
top: 10;
left: 100;
visibility: hidden;
}
</style>
JS:
<!-- JAVASCRIPT -->
<script language="JavaScript">
var currentLayer = 'page1';
function showLayer(lyr) {
hideLayer(currentLayer);
document.getElementById(lyr)
.style.visibility = 'visible';
currentLayer = lyr;
}
function hideLayer(lyr) {
document.getElementById(lyr).
style.visibility = 'hidden';
}
function showValues(form) {
var values = '';
var len = form.length - 1;
//Leave off Submit Button
for (i = 0; i < len; i++) {
if (form[i].id.indexOf("C") != -1 ||
form[i].id.indexOf("B") != -1)
//Skip Continue and Back Buttons
continue;
values += form[i].id;
values += ': ';
values += form[i].value;
values += '\n';
}
alert(values);
}
</script>
i think you mean something like this:
let currentLayer = 0;
const animalList = [];
const form = document.getElementById("wf-form-Email-Form");
const [field, backButton, addButton, submitButton] = form.elements;
function showLayer(lyr) {
switch(lyr){
case 1:
currentLayer++;
if (currentLayer-1 == animalList.length){
animalList.push(field.value)
form.reset();
backButton.style.display = 'unset';
}else{
if (currentLayer == animalList.length){
addButton.value = 'Add another animal';
field.value = "";
}else{
addButton.value = 'Next';
field.value = animalList[currentLayer];
}
}
break;
case -1:
currentLayer--;
if(!currentLayer) backButton.disabled = true;
if (currentLayer < animalList.length +1){
field.value = animalList[currentLayer];
addButton.value = 'Next';}
break;
}
}
submitButton.onClick = function(e){
// serialize animalList and send using AJAX or add a hidden type input and set animalList as it's value
}
.page {
position: absolute;
top: 10;
left: 100;
visibility: hidden;
}
#backButton{
display:none;
}
<div class="section-25">
<div class="container-5 w-container">
<div class="text-block-6">Select the level of algorithm you're looking to make</div>
<div class="w-form">
<form id="wf-form-Email-Form" name="wf-form-Email-Form" data-name="Email Form" method="post" action="/add_animal">
<label for="Enter-species" class="custom-question enter-species" id="one_name">What other animal are you interested in?</label>
<input type="text" class="text-field w-input" maxlength="256" name="another_species" placeholder="Enter name of animal" id="Enter-species">
<p>
<input type="button" id="backButton" value="Go Back" onClick="showLayer(-1)">
<input type="button" id="addButton" value="Add another animal" onClick="showLayer(+1)">
<input type="button" id="submit" value="Submit">
</p>
</form>
</div>
</div>
</div>

How to get input submission to stay on screen instead of flashing across

I am currently trying to create a tip calculator app using JS, HTML, and CSS. My issue is that the input value is submitted when the button is clicked, but once submitted, the value just flashes for less than a second, then it vanishes. I would like for the value to stay on the screen once submitted.
let dinTotal = document.querySelector('#cost');
let dinService = document.querySelector('#service');
let dinSize = document.querySelector('#size');
let calcBtn = document.querySelector('button');
let total = 0;
let amount = document.querySelector('#amount')
calcBtn.addEventListener('click', function() {
if(dinTotal.value >= 50 && dinService.value < 5 && dinSize.value < 5) {
total = (dinTotal.value * 0.10) + dinTotal.value ;
amount.textContent = total;
}
})
<form>
<h1>Tip & Dip✌️</h1>
<hr>
<!-- Bill Section -->
<div>
<label for='cost'>Dinning amount</label>
</div>
<input name='cost' id='cost' type='number' placeholder='$' required>
<!-- Service Section-->
<div class='top-space'>
<label for='service'>How was the service</label>
</div>
<input name='service' id='service' type='number' placeholder='rate 1-10' required>
<!-- Party Size-->
<div class='top-space'>
<label for='size'>Party Size</label>
</div>
<div>
<input name='size' id='size' type='number' required>
</div>
<div class='top-space'>
<button>LET'S CALCULATE...</button>
</div>
<hr>
<h2>Total: $<span id='amount'>0</span></h2>
</form>
The default behavior of a button is to submit the form. When a form submits, if you don't stop it, it will unload the current page and submit the data to its action URL. With no action attribute, a form submits to the current page, causing your reload.
Set the type attribute on your button to button to prevent it from being a submit button.
<button type="button">LET'S CALCULATE...</button>
use the preventDefualt() method of the event callback
calcBtn.addEventListener('click', function(event) {
event.preventDefault()
}
Full working snippet (though it only updates for size and value of less than 5 and checks greater than 50 I hope you know)
let dinTotal = document.querySelector('#cost');
let dinService = document.querySelector('#service');
let dinSize = document.querySelector('#size');
let calcBtn = document.querySelector('button');
let total = 0;
let amount = document.querySelector('#amount')
calcBtn.addEventListener('click', function(event) {
event.preventDefault()
if(dinTotal.value >= 50 && dinService.value < 5 && dinSize.value < 5)
{
total = (dinTotal.value * 0.10) + dinTotal.value ;
console.log(total)
amount.textContent = total;
}
})
<form>
<h1>Tip & Dip✌️</h1>
<hr>
<div>
<label for='cost'>Dinning amount</label>
</div>
<input name='cost' id='cost' type='number' placeholder='$' required>
<div class='top-space'>
<label for='service'>How was the service</label>
</div>
<input name='service' id='service' type='number' placeholder='rate 1-10' required>
<div class='top-space'>
<label for='size'>Party Size</label>
</div>
<div>
<input name='size' id='size' type='number' required>
</div>
<div class='top-space'>
<button>LET'S CALCULATE...</button>
</div>
<hr>
<h2>Total: $<span id='amount'>0</span></h2>
</form>

cloneNode and total the value of all nodes (parent+childs). Javascript

I want to total the values of all input, but in the beginning there's only one input element and you add the clone(s) with a button. Actually I have two issues:
1. How to place the clone node always under the node before it.
2. How to total the values of all nodes.
Here's the code:
function nambahData() {
var a = document.getElementById("harga");
var b = a.cloneNode(false);
document.getElementById("form").appendChild(b);
}
function ditotal() {
var x = document.getElementById("harga").value;
var y = document.getElementById("harga").childNode.value;
document.getElementById("total").value = parseInt(x) + parseInt(y);
}
</script>
<div id="form">
<input id="harga" type=number>
<br>
</div>
<button onclick="nambahData()">add data</button>
<br>
<button onclick="ditotal()">total all</button>
<input id="total" type=number>
Hope this helps you ..
window.nambahData = function() {
var a = document.getElementsByName("harga");
var b = a[0].cloneNode(false);
document.getElementById("form").appendChild(b);
}
window.ditotal = function() {
var totalItems = 0;
for(i=document.getElementsByName("harga").length-1;i>=0;i--)
{
var item = document.getElementsByName("harga")[i];
totalItems += parseFloat(item.value);
}
document.getElementById("total").value = totalItems;
}
.inputStyle{
display:block;
}
<div id="form">
<input name="harga" type="number" class="inputStyle">
</div>
<button onclick="nambahData()">add data</button>
<br>
<button onclick="ditotal()">total all</button>
<input id="total" type=number>

Categories

Resources