I set up two events, one in feet and one in inches. I'm trying to grab the value of each event which would be feet and inches but I can't because of each event's scope. Is there a way to pass both values into my totalHeight function so that I can add the two values together?
const justFeet = totalFeet.addEventListener('input', (e) => {
const heightInFeet = e.target.value;
let displayFeet = document.createElement('h3')
displayFeet.textContent = heightInFeet * 12
// totalInches.appendChild(displayFeet)
})
const justInches = inches.addEventListener('input', (e) => {
const addOnInches = e.target.value;
let displayInches = document.createElement('h3')
displayInches.textContent = addOnInches
// totalInches.appendChild(displayInches)
})
function totalHeight (feet, inches) {
const finalTotal = feet + inches;
let finalHeight = document.createElement('h3')
finalHeight.textContent = finalTotal
totalInches.appendChild(finalHeight)
}
totalHeight(displayFeet, displayInches)
An example of what it looks like you are trying to do. There's more you need to do, for example I used integers below but you could use floating numbers and perhaps add better handling for isNaN().
<html>
<style>
</style>
Feet:<input id="feet" type="number"></input>
Inches:<input id="inches" type="number"></input>
<h3>Feet converted to inches: <span id="displayFeetToInches"></span></h3>
<h3>Inches: <span id="displayInches"></span></h3>
<h3>Total inches:<span id="finalHeight"></span></h3>
<script>
const feet = document.getElementById("feet");
const inches = document.getElementById("inches");
const total = document.getElementById("total"); //in inches
const displayFeetToInches = document.getElementById("displayFeetToInches"); //in inches
const displayInches = document.getElementById("displayInches"); //in inches
const justFeet = feet.addEventListener('input', (e) => {
console.log('justFeet');
const heightInFeet = e.target.value;
displayFeetToInches.textContent = heightInFeet * 12;
totalHeight();
})
const justInches = inches.addEventListener('input', (e) => {
console.log('justInches');
const addOnInches = e.target.value;
displayInches.textContent = addOnInches
totalHeight();
})
function totalHeight (feet, inches) {
console.log('totalinches');
const ftToInches = displayFeetToInches.textContent;
const addOn = displayInches.textContent;
const finalTotal = parseInt(ftToInches) + parseInt(addOn);
finalHeight.textContent = finalTotal
}
</script>
</html>
Related
I have a problem with adding a function which will create an amount of boxes with rising size and when i try to add more I will start from the size of the previous last box.
So far i have a code like this:
function getRandomHexColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
const input = document.querySelector("#controls>input");
const createBtn = document.querySelector("button[data-create]");
const destroyBtn = document.querySelector("button[data-destroy]");
const boxCollection = document.querySelector("#boxes");
const createBoxes = (amount) => {
amount = input.value;
for (let i = 0; i < amount; i += 1) {
let newBox = document.createElement("div");
newBox.style.height = `${30 + 10 * i}px`;
newBox.style.width = `${30 + 10 * i}px`;
newBox.style.background = getRandomHexColor();
boxCollection.insertAdjacentElement("beforeend", newBox);
}
};
createBtn.addEventListener("click", createBoxes);
const destroyBoxes = () => {
boxCollection.innerHTML = "";
};
destroyBtn.addEventListener("click", destroyBoxes);
I was thinking about adding a new var which will be the lastChild of const boxCollection and add it to height and width of newBox. Am I thinking right?
You can either create a variable with the current number of boxes or you can just count the current number each time you add more. In the example the current number (currentCount) is based on the length of a querySelectorAll().
function getRandomHexColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
const boxCollection = document.querySelector("#boxes");
const createBoxes = e => {
e.preventDefault();
let amount = parseInt(e.target.amount.value);
let currentCount = boxCollection.querySelectorAll('div').length;
Object.keys([...Array(amount)]).forEach(i => {
let incVal = parseInt(i) + currentCount;
let newBox = document.createElement("div");
newBox.style.height = `${30 + 10 * incVal}px`;
newBox.style.width = `${30 + 10 * incVal}px`;
newBox.style.background = getRandomHexColor();
boxCollection.insertAdjacentElement("beforeend", newBox);
});
};
const destroyBoxes = e => {
e.preventDefault();
boxCollection.innerHTML = "";
};
document.forms.create.addEventListener("submit", createBoxes);
document.forms.destroy.addEventListener("submit", destroyBoxes);
<form name="create">
<input type="number" name="amount" />
<button>Create</button>
</form>
<form name="destroy">
<button>Destroy</button>
</form>
<div id="boxes"></div>
You could hold the latest size of the box in a var.
function getRandomHexColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
const input = document.querySelector("#controls>input");
const createBtn = document.querySelector("button[data-create]");
const destroyBtn = document.querySelector("button[data-destroy]");
const boxCollection = document.querySelector("#boxes");
let currentBoxSize = 30 // starting box size
const BOX_SIZE_INCREMENT = 10 // increment size
const createBoxes = (amount) => {
amount = input.value;
for (let i = 0; i < amount; i += 1) {
let newBox = document.createElement("div");
newBox.style.height = `${currentBoxSize}px`;
newBox.style.width = `${currentBoxSize}px`;
newBox.style.background = getRandomHexColor();
boxCollection.insertAdjacentElement("beforeend", newBox);
currentBoxSize += BOX_SIZE_INCREMENT
}
};
createBtn.addEventListener("click", createBoxes);
const destroyBoxes = () => {
boxCollection.innerHTML = "";
};
destroyBtn.addEventListener("click", destroyBoxes);
Just store the last input value in a variable, or if you want to preserve the state, you can store it in locale storage, and when you click create boxes, sum it with the value with the new input value.
function getRandomHexColor() {
return `#${Math.floor(Math.random() * 16777215).toString(16)}`;
}
const input = document.querySelector("#controls>input");
const createBtn = document.querySelector("button[data-create]");
const destroyBtn = document.querySelector("button[data-destroy]");
const boxCollection = document.querySelector("#boxes");
let lastInputValue = 0;
const createBoxes = (amount) => {
amount = input.value + lastInputValue;
for (let i = 0; i < amount; i += 1) {
let newBox = document.createElement("div");
newBox.style.height = `${30 + 10 * i}px`;
newBox.style.width = `${30 + 10 * i}px`;
newBox.style.background = getRandomHexColor();
boxCollection.insertAdjacentElement("beforeend", newBox);
}
lastInputValue = amount;
};
createBtn.addEventListener("click", createBoxes);
const destroyBoxes = () => {
boxCollection.innerHTML = "";
};
destroyBtn.addEventListener("click", destroyBoxes);
I am having a hard time trying to figure out how to get the the value from every new Li and reduce it (add) to then output to my h2. Can't figure out what I am doing wrong. Any help would be greatly appreciated! Codepen: https://codepen.io/Chasehud26/pen/Poagjwy
I tried to console.log different variables to see if there were any hints of what is going wrong.
const form = document.querySelector("form")
const nameInput = document.querySelector("#name-input")
const priceInput = document.querySelector("#price-input")
const button = document.querySelector("button")
const nameUl = document.querySelector("#item-name")
const priceUl = document.querySelector("#item-price")
const h2 = document.querySelector("h2")
const nameLi = document.createElement("li")
const priceLi = document.createElement("li")
form.addEventListener("submit", function (e) {
e.preventDefault()
let nameVal = nameInput.value
let priceVal = priceInput.value
const nameLi = document.createElement("li")
const priceLi = document.createElement("li")
nameUl.appendChild(nameLi)
nameLi.innerHTML = nameInput.value
priceUl.appendChild(priceLi)
priceLi.textContent = `${priceInput.value}`
showTotals()
})
//TRYING TO ADD TOGETHER ALL THE PRICE VALUES AND THEN PUT IT TO MY H2//
function showTotals() {
const priceList = document.querySelectorAll("li")
for (let priceLists of priceList) {
const total = []
total.push(parseFloat(priceLists.textContent));
const totalMoney = total.reduce(function (total, item) {
total += item;
return total;
}, 0);
const finalMoney = totalMoney.toFixed(2);
h2.textContent = finalMoney;
}
}
You need to have your const total [] array initialized outside of the for loop. also, when you setup your <li> decorators, you need to differentiate between the number and non-number fields, since the way you had it, it was trying to add the text 'li' fields also:
/// truncated for clarity
const nameLi = document.createElement("li")
const priceLi = document.createElement("li")
priceLi.classList.add('num') // <== this line added
//// =================
function showTotals() {
const priceList = document.querySelectorAll("li.num") // added class
const total = [] // <== move this to here
for (let priceLists of priceList) {
total.push(parseFloat(priceLists.textContent));
const totalMoney = total.reduce(function (total, item) {
total += item;
return total;
}, 0);
const finalMoney = totalMoney.toFixed(2);
h2.textContent = finalMoney;
}
After filling in the form inputs, When i press the calculate button on the form the result does not get displayed in the salary slip box(At the bottom of the box).
But when i do refresh the page and then press the calculate button the results do get displayed in the box.
Here is the link to the code:
JsfiddleLink
"use strict";
const employeeName = document.querySelector("#input-name").value;
const grossPay = document.querySelector("#input-pay").value;
const bonus = document.querySelector("#input-bonus").value;
const allowance = document.querySelector("#input-allowance").value;
const incomeTax = document.querySelector("#input-tax").value;
const ei = document.querySelector("#input-ei").value;
const cpp = document.querySelector("#input-cpp").value;
const selectGender = document.querySelector(
'input[name="gender"]:checked'
).value;
const selectDependent = document.querySelector(
'input[name="dependent"]:checked'
).value;
const btnCalculate = document.querySelector("#submit");
const btnClear = document.querySelector("#clear");
const myForm = document.querySelectorAll(".form-control");
let inputAll = document.querySelectorAll("input");
function addition(bonus, allowance) {
let total = Number(bonus) + Number(allowance);
return total;
}
function deduction(ei, cpp) {
let total = (Number(ei) + Number(cpp)) / 100;
return total;
}
// console.log(addition(bonus, allowance));
// console.log(deduction(incomeTax, ei, cpp));
// gross salary plus additions minus deductions
// if female employee then minus 1%
// else deduction is 0
// if dependents === 2 then no deductions
// if dependents === 3 then 2 % deduction
// else if dependents === 4 then 4% deductions
// display the results on the salary slip
function genderDeduction(selectGender) {
return selectGender === "Female" ? 0.01 : null;
}
function dependentDeduction(selectDependent) {
if (selectDependent === "1") {
return null;
} else if (selectDependent === "2") {
return 0.02;
} else if (selectDependent === "3") {
return 0.04;
}
}
function incomeTaxDeduction(incomeTax) {
return Number(incomeTax) / 100;
}
// console.log(genderDeduction("Female"));
// console.log(dependentDeduction("2"));
let totalAdditions = addition(bonus, allowance);
let totalDeductions = Number(
grossPay * deduction(ei, cpp) +
grossPay *
(incomeTaxDeduction(incomeTax) -
genderDeduction(selectGender) -
dependentDeduction(selectDependent))
);
totalDeductions.toFixed(2);
function finalSalary(grossPay) {
return Number(grossPay) + totalAdditions - totalDeductions;
}
const nameSlip = document.querySelector(".name");
const grossSalary = document.querySelector(".gross-salary");
const sumOfAdditions = document.querySelector(".total-additions");
const sumOfDeductions = document.querySelector(".total-deductions");
const netSalary = document.querySelector(".final-salary");
// function salarySlip() {}
// function clearInput() {
// employeeName = "";
// grossPay = "";
// }
btnCalculate.addEventListener("click", (e) => {
e.preventDefault();
nameSlip.innerText = employeeName;
grossSalary.innerText = `$ ${grossPay}`;
sumOfAdditions.innerText = `$ ${totalAdditions}`;
sumOfDeductions.innerText = `$ ${totalDeductions.toFixed(2)}`;
netSalary.innerText = `$ ${finalSalary(grossPay)}`;
});
// btnClear.addEventListener("click", () => {
// myForm.reset();
// });
You have the following declaration:
<button
onclick="clearInput"
id="submit"
type="submit"
class="btn btn-primary"
>
Calculate
</button>
So you have to declare a function called "clearInput" to handle the button click event.
To solve your problem, you can modify the above declaration as below:
<button
id="submit"
type="submit"
class="btn btn-primary"
>
Calculate
</button>
And then add the below statements.
let myForm=document.getElementById("my-form");
myForm.addEventListener("submit",(e)=>{
//do your work here
e.preventDefault();
})
I've partially updated your code here: https://jsfiddle.net/y7hbnv18/1/
what I did:
updated all inputs to have a name property.
created a reference to the <form /> element in JS
updated the listener on submit button to be on the form instead
used the FormData API to retrieve the data from the form.
it's still somewhat in a broken state, in the last few fields, but I think you'll figure it out from here.
You need to move the code that gets the values to the body of the event handler function.
btnCalculate.addEventListener("click", (e) => {
e.preventDefault();
const employeeName = document.querySelector("#input-name").value;
const grossPay = document.querySelector("#input-pay").value;
const bonus = document.querySelector("#input-bonus").value;
const allowance = document.querySelector("#input-allowance").value;
const incomeTax = document.querySelector("#input-tax").value;
const ei = document.querySelector("#input-ei").value;
const cpp = document.querySelector("#input-cpp").value;
const selectGender = document.querySelector(
'input[name="gender"]:checked'
).value;
const selectDependent = document.querySelector(
'input[name="dependent"]:checked'
).value;
let totalAdditions = addition(bonus, allowance);
let totalDeductions = Number(
grossPay * deduction(ei, cpp) +
grossPay *
(incomeTaxDeduction(incomeTax) -
genderDeduction(selectGender) -
dependentDeduction(selectDependent))
);
totalDeductions.toFixed(2);
nameSlip.innerText = employeeName;
grossSalary.innerText = `$ ${grossPay}`;
sumOfAdditions.innerText = `$ ${totalAdditions}`;
sumOfDeductions.innerText = `$ ${totalDeductions.toFixed(2)}`;
netSalary.innerText = `$ ${finalSalary(grossPay, totalAdditions, totalDeductions)}`;
});
Also update the finalSalary function so you can pass in totalAdditions and totalDeductions the signature should be
function finalSalary(grossPay, totalAdditions, totalDeductions)
You may also need to change the button type to button from submit to stop the form being submitted as this will refresh the page.
<button
onclick="clearInput"
id="submit"
type="button"
class="btn btn-primary"
>
Calculate
</button>
I'm new to JS so I have been writing code the most simple way possible for me just to get the functionality that I want the plan being clean it up and shorten everything later.
Part of doing this I have loads of classes to select a series of elements by their id. Is it possible to put these in an array? all the elements are numbered 1-12
Essentially I have three items to get a slide its accompanying audio and subtitle
const slide0 = document.getElementById("slide0");
const slide1 = document.getElementById("slide1");
const slide2 = document.getElementById("slide2");
const slide3 = document.getElementById("slide3");
const slide4 = document.getElementById("slide4");
const slide5 = document.getElementById("slide5");
const slide6 = document.getElementById("slide6");
const slide7 = document.getElementById("slide7");
const slide8 = document.getElementById("slide8");
const slide9 = document.getElementById("slide9");
const slide10 = document.getElementById("slide10");
const slide11 = document.getElementById("slide11");
const slide12 = document.getElementById("slide12");
const subt1 = document.getElementById("sub1");
const subt2 = document.getElementById("sub2");
const subt3 = document.getElementById("sub3");
const subt4 = document.getElementById("sub4");
const subt5 = document.getElementById("sub5");
const subt6 = document.getElementById("sub6");
const subt7 = document.getElementById("sub7");
const subt8 = document.getElementById("sub8");
const subt9 = document.getElementById("sub9");
const subt10 = document.getElementById("sub10");
const subt11 = document.getElementById("sub11");
const subt12 = document.getElementById("sub12");
const chp1 = document.getElementById("audiochp1");
const chp2 = document.getElementById("audiochp2");
const chp3 = document.getElementById("audiochp3");
const chp4 = document.getElementById("audiochp4");
const chp5 = document.getElementById("audiochp5");
const chp6 = document.getElementById("audiochp6");
const chp7 = document.getElementById("audiochp7");
const chp8 = document.getElementById("audiochp8");
const chp9 = document.getElementById("audiochp9");
const chp10 = document.getElementById("audiochp10");
const chp11 = document.getElementById("audiochp11");
const chp12 = document.getElementById("audiochp12");
Yes, you can. For example:
let slides = [];
for (let i = 0; i < num_slides; i++) {
slides.push({
slide: document.getElementById(`slide${i}`),
subt: document.getElementById(`sub${i}`),
chp: document.getElementById(`audiochp${i}`)
});
}
You could, however, also do something similar by giving your elements classes and then using document.getElementsByClassName('slide') and so on.
Surely! I highly advise you to generate a few helper functions for this. Take a look at the following example:
function getSlides(theMaxSlideNumer) {
const returnElements = [];
for (int i = 0; i <= theMaxSlideNumber; i++) {
const aSlideQuery = "#slide" + i.toString();
returnElements.push(document.querySelector(aSlideQuery));
}
return returnElements;
}
const slides = getSlides(12);
Add safeguard
function getSlides(theMaxSlideNumer) {
const returnElements = [];
for (int i = 0; i <= theMaxSlideNumber; i++) {
const aSlideQuery = "slide" + i.toString();
returnElements.push(document.querySelector(aSlideQuery));
}
returnElements.forEach((aElement)=>{
if (aElement === null) console.warn("A dom element could not be found, trace this message!");
});
return returnElements;
}
const slides = getSlides(12);
Target them using querySelectorAll and spread them into an array.
[...document.querySelectorAll('[id^=slide]')] // CSS selector that captures all elements starting with slide word
Repeat for each group you have.
Fiddle: https://jsfiddle.net/dk9f86rp/19/
I have a UI with x input boxes. I want the values in the boxes to increase by 1 from left to right. The functionality like in this plunk: https://plnkr.co/edit/82sNDb?p=preview .
const inputValue = element =>
Rx.Observable.fromEvent(element, 'input').map(e =>
parseInt(e.target.value, 10));
const box1$ = inputValue(box1);
const box2$ = inputValue(box2);
const box3$ = inputValue(box3);
box1$.subscribe((val) => {
box2.value = val + 1;
box3.value = val + 2;
});
box2$.subscribe((val) => {
box1.value = val - 1;
box3.value = val + 1;
});
box3$.subscribe((val) => {
box1.value = val - 2;
box2.value = val - 1;
});
Trying to scale that for more boxes seems hard though so I tried to chain them together instead; where change in one box propagates to the 'next' box.
I cant seem to do that in a none complicated way though and resorted to use subjects to push values to the streams. Is there a cleaner way to do this?
My chained implementation: https://plnkr.co/edit/tbM5Gh?p=preview
window.addEventListener('DOMContentLoaded', () => {
const box1 = document.querySelector('#box1');
const box2 = document.querySelector('#box2');
const box3 = document.querySelector('#box3');
const box1Subject = new Rx.Subject();
const box2Subject = new Rx.Subject();
const box3Subject = new Rx.Subject();
// link box1 -> box2
const box1$ = createBoxStream(box1)(box1Subject)(val => val + 1)
.subscribe((newValue) => {
box2.value = newValue;
box2Subject.next(newValue);
});
// link box2 -> box3
const box2$ = createBoxStream(box2)(box2Subject)(val => val + 1)
.subscribe((newValue) => {
box3.value = newValue;
box3Subject.next(newValue);
});
// link box3 -> box1
const box3$ = createBoxStream(box3)(box3Subject)(val => val - 2)
.subscribe((newValue) => {
box1.value = newValue;
box1Subject.next(newValue);
});
});
const createBoxStream = element => subject => projection => Rx.Observable
.fromEvent(element, 'input')
.map(e => parseInt(e.target.value, 10))
.merge(subject)
.map(projection)
.distinctUntilChanged();
I would go with slightly different approach, we could merge streams from all inputs and update input boxes accordingly. Such solution will work for any number of input boxes:
window.addEventListener('DOMContentLoaded', () => {
const boxesCount = 3;
const boxes = [];
let $allBoxesInput = null;
const keyUp = el => Rx.Observable.fromEvent(el, 'keyup');
for (let i = 0; i < boxesCount; i++) {
const el = document.querySelector(`#box${i}`);
boxes.push(el);
$allBoxesInput = $allBoxesInput ?
Rx.Observable.merge($allBoxesInput, keyUp(el)) : keyUp(el);
}
$allBoxesInput.distinctUntilChanged()
.subscribe(event => {
// we get all events here
const id = event.target.id;
const index = parseInt(id.substr(id.length - 1, id.length));
const value = event.target.value;
// update all at the right
for (let i = index + 1; i < boxes.length; i++) {
boxes[i].value = parseInt(boxes[i - 1].value) + 1;
}
});
});
I started ids with 0 to be more array index friendly:
<body>
<input type="text" id="box0">
<input type="text" id="box1">
<input type="text" id="box2">
</body>