I only need a function so that I can divide #total by the total of names that were entered on the button. If you know the answer please help me, I'm a newbie in Javascript.
function ir() {
const nombre = document.getElementById("nombre").value;
let monto = document.getElementById("monto").value;
const total = document.getElementById("total");
const final = document.getElementById("final");
const aporte = document.getElementById("aporte");
const lineBreak = document.createElement("br");
let newTotal = document.createTextNode(` ${nombre} : ${monto} `);
total.appendChild(lineBreak);
total.appendChild(newTotal);
monto = Number(monto) Number(final.innerHTML);
final.innerHTML = `${monto}`;
aporte.innerHTML = `${monto}`;
};
<h1>Expenses app</h1>
<p>Enter how much each person spent</p>
<p>Nombre</p>
<input type="text" id="nombre">
<br>
<p>Monto</p>
<input type="number" id="monto">
<br>
<button onclick="ir()">Enviar</button>
<br>
<p>Total: <span id="final"></span> </p>
<div id="total">
</div>
<p>A cada uno le toca aportar: <span id="aporte"></span></p>
CodePudding user response:
Sorry I can't fully understand the meanings of your attributes' name, I guess 'nombre' is names of people and 'monto' means amount of all money. If so:
Maybe you need split method to count the amount of names, like:
const names = 'name1,name2,name3'
// divide above string by ','
const nameArray = names.split(',') // ['name1', 'name2', 'name3']
// get the amount of names
const count = nameArray.length // 3
then use arithmetic operators to get what you need.
If you want to show everyone's money, you can use forEach (different from map) to do something, like:
const nameArray = ['name1', 'name2', 'name3']
const money = { name1: 10, name2: 20, name3: 30 }
// you can use forEach
nameArray.forEach((name) => {
// this function will run 3 times,
// and the name attribute will be 'name1' 'name2' 'name3' respectively
console.log(`${name}: ${money[name]}`)
// you can do something here, for example, operate document
})
// or use map
const resultStringArray = nameArray.map((name) => {
return `${name}: ${money[name]}`
})
// resultStringArray = ['name1: 10', 'name2: 20', 'name3: 30']
CodePudding user response:
i hope this fast written solution helps you.
var Persons = [];
window.onload = () => {
var PersonHTMLElement = document.getElementById("person");
var AmountHTMLElement = document.getElementById("amount");
var TotalHTMLElement = document.getElementById("total");
var PersonListHTMLElement = document.getElementById("final");
var TotalDividedHTMLElement = document.getElementById("aporte");
document.getElementById("calc").addEventListener("click", setPerson);
function setPerson(){
let person = PersonHTMLElement.value;
let amount = AmountHTMLElement.value;
Persons.push({
Name:person,
Amount:parseFloat(amount)
});
PersonHTMLElement.value = "";
AmountHTMLElement.value = "";
setTotal();
}
function setTotal(){
TotalHTMLElement.innerHTML = "";
let PersonsList = "";
let Total = 0;
for(let i = 0;i < Persons.length; i ){
Total = Persons[i].Amount;
PersonsList = `${Persons[i].Name}: ${Persons[i].Amount} <br>`;
}
TotalHTMLElement.innerHTML = PersonsList;
PersonListHTMLElement.innerHTML = Total;
TotalDividedHTMLElement.innerHTML = Total / Persons.length;
}
}
<html>
<head>
<script src="myscript.js"></script>
</head>
<body>
<h1>Expenses app</h1>
<p>Enter how much each person spent</p>
<p>Nombre</p>
<input type="text" id="person">
<br>
<p>Monto</p>
<input type="number" id="amount">
<br>
<br>
<button id="calc">Enviar</button>
<br>
<p>Total: <span id="final"></span> </p>
<div id="total">
</div>
<p>A cada uno le toca aportar: <span id="aporte"></span></p>
</body>
</html>
CodePudding user response:
While you've already accepted an answer, I wanted to take the time to show another approach; hopefully anticipating some of your requirements. Explanatory comments are in the code itself:
// I create a few utility functions and variables to make things a
// little easier; here we cache the document variable in order to
// reduce typing the whole word:
const D = document,
// creating an alias for document.createElement():
create = (elem) => D.createElement(elem),
// a simple alias for both document.querySelector() or
// Element.querySelector(); with the default value of
// context being equal to document:
get = (selector, context = D) => context.querySelector(selector),
// an alias - as above - for document.querySelectorAll() or
// Element.querySelectorAll(), again with the default context
// argument set to document; here though we return an Array
// of element nodes in order to utilise Array methods:
getAll = (selector, context = D) => [...context.querySelectorAll(selector)],
// a simple function to handle the removal of a person once added, this
// function (as do all event-handler functions) pass in a reference to
// the Event Object ('evt') to the function-body:
removePerson = (evt) => {
// the Event Object's currentTarget property-value is a reference to
// the Element to which the event-handler (this function) was bound:
let currentTarget = evt.currentTarget,
// the Event Object's target property-value is the Element that
// initially triggered the event:
target = evt.target;
// if the user has clicked on the <ul> we return false, and effectively
// do nothing:
if (target === currentTarget) {
return false;
// otherwise we check if the target matches the supplied CSS selector,
// using Element.matches(), which returns a Boolean true (if the
// Element does match the selector) or false (if the Element does not
// match that selector):
} else if (target.matches('span.delete')) {
// if the element matches, then we navigate the DOM from that target
// Element, and find the closest ancestor element that matches the
// supplied CSS selector; if no such element is found then null is
// returned (and this has no sanity checks to ensure that an error
// is safely handled); that <li> element is then removed:
target.closest('li').remove();
}
},
// this function is another event-handler, and again passes in a reference
// to the Event Object:
addPeople = (evt) => {
// the element to which the function was bound as an event-handler:
let activated = evt.currentTarget,
// here we use the utility function to find the element with an
// 'id' of 'name':
name = get('#name'),
// from that element we retrieve the value, and then use
// String.prototype.trim() to remove leading and trailing white-space:
givenName = name.value.trim(),
// we use another utility function to create an <li> element:
li = create('li'),
// here we use the getAll() utility function to search for <option>
// elements in the <datalist> associated with the name element
allNames = getAll('option', name.list)
// we then use Array.prototype.map() to iterate over that Array
// of element-nodes to create a new Array:
.map(
// using an Arrow function, passing in a reference to the current
// element ('el') of the Array of elements, and here we return
// the textContent of the current <option> element:
(el) => el.textContent
),
// creating the remove button:
removeButton = create('span');
// adding the 'delete' class-name, using the Element.classList API:
removeButton.classList.add('delete');
// assigning the template-literal string - interpolating the value
// of the givenName variable - as the title property of the
// created 'button':
removeButton.title = `Click to remove ${givenName}`;
// I could have used the optional chaining parameter to avoid errors:
// if (givenName?.length) {
// but writing this 'quickly' in JS Fiddle, which doesn't understand
// that operator, was causing issues every time I formatted, so I went
// with the 'traditional' approach:
if (givenName && givenName.length) {
// setting the text-content of the <li> to the givenName:
li.textContent = givenName;
// appending the removeButton element:
li.append(removeButton);
// finding the element matching the CSS selector, within the <form>
// associated with the activated element, and then appending the <li>:
get('ul.people', activated.form).append(li);
// if the list of names held in the <datalist> element's <option> elements
// does not include the givenName:
if (allNames.includes(givenName) === false) {
// we then append a new Option element, with the givenName as its text:
name.list.append(new Option(givenName))
}
// and here we set the value of the name element to be an empty string:
name.value = '';
}
},
// the function to handle calculating the total, again an event-handler passing
// in a reference to the Event Object:
total = (evt) => {
// finding the element to which the function was bound:
let activated = evt.currentTarget,
// finding the associated <form> of that element:
form = activated.form,
// finding the <li> elements which match the selector inside
// of the <form> element:
participants = getAll('ul.people li', form),
// the number of participants:
numberOfParticipants = participants.length,
// finding the element with the id of 'total':
total = get('#amount'),
// calling parseFloat on the trimmed-value of that element:
totalValue = parseFloat(total.value.trim()),
// finding the <output> and <aside> elements within the <form>:
output = get('output', form),
aside = get('aside', form);
// if the value is less than zero:
if (totalValue < 0) {
// we convert the value of the <input> to the absolute-value given:
total.value = Math.abs(totalValue);
// we update the <aside> element to leave a "helpful" message:
aside.textContent = "No, we don't use negative numbers."
// if the totalValue is not a number (isNaN), or is potentially infinite (divide-by-zero),
// or is somehow falsey (!totalValue) or is equal to zero:
} else if (isNaN(totalValue) || !isFinite(totalValue) || !totalValue || totalValue === 0) {
// we update the value of the <input> to zero:
total.value = 0;
// and leave a "helpful" message:
aside.textContent = "Honestly, we'd rather work with sensible numbers."
// if there are no participants, or the number of participants is falsey:
} else if (numberOfParticipants === 0 || !numberOfParticipants) {
// we do nothing, except leave a helpful message:
aside.textContent = "If no-one's splitting the bill, what are we doing? Is anybody there?"
// if we get to this point:
} else {
// and the number of participants is only 1:
if (numberOfParticipants === 1) {
// again, "helpful" message (it was around this point I realised I was getting
// hungry):
aside.textContent = "We're glad to help, but this does seem a bit unnecessary."
// otherwise:
} else {
// we remove the text of the <aside>:
aside.textContent = '';
}
// here is where we set the <output>:
output.textContent = (
// using Math.ceil() to round up to the next/nearest integer (of cents):
Math.ceil(
// because we're dealing with currency I multiply the number by 100,
// to convert €9.99 to 999, this allows us to use Math.ceil() to
// round up to the nearest cent:
100 * (totalValue / numberOfParticipants)
// here we divide by 100 to allow for the value to be returned in € and c
) / 100
// and because - again - this is currency, we convert the number to
// a String, with two decimal places (for the cents):
).toFixed(2);
}
};
// finding the element that matches the selector, and calling
// EventTarget.addEventListener() to bind the addPeople() function
// as the 'click' event-handler:
get('button.minor-button').addEventListener('click', addPeople);
// here we find the element with the id of 'name', and again we use
// EventTarget.addEventListener() but this time we use its anonymous
// function to evaluate the keypress event:
get('#name').addEventListener('keypress', (evt) => {
// if the key is 'Enter' or has the keyCode of 13:
if ('Enter' === evt.key || 13 === evt.keyCode) {
// we then call the addPeople function, and supply the Event Object:
addPeople(evt);
}
});
// exactly as above, but binding the total() function as the 'click'
// event-handler:
get('#calculate').addEventListener('click', total);
// getting the element matching the selector, chaining addEventListener()
// to bind the removePerson() function as the 'click' event-handler:
get('form ul.people').addEventListener('click', removePerson);
:root {
--border: 1px solid hsl(120 40% 40%);
--color: hsl(120 40% 20%);
--hint-color: hsl(120 40% 40%);
--spacing: 0.5rem;
--numColumns: 2;
--maxColSpan: 2;
--rowHeight: 1fr;
}
*,
::before,
::after {
box-sizing: border-box;
color: var(--color);
margin: 0;
padding: 0;
}
::before,
::after {
color: var(--hint-color);
font-style: italic;
}
form {
display: grid;
gap: var(--spacing);
grid-template-columns: repeat(var(--numColumns), 1fr);
grid-template-rows: repeat(3, var(--rowHeight));
margin-block: calc(2*var(--spacing));
margin-inline: auto;
width: clamp(30em, 80vw, 1000px);
}
form>* {
border: var(--border);
grid-row: span 1;
}
form> :empty {
border-color: transparent;
}
fieldset {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-row: span var(--maxColSpan);
gap: var(--spacing);
padding: var(--spacing);
}
legend {
display: block;
}
button {
grid-column: span 2;
}
.minor-button {
grid-column: 2;
}
legend::after,
label::after {
content: ':';
}
ul.people {
border-color: var(--border);
display: flex;
flex-flow: row wrap;
gap: var(--spacing);
align-content: start;
list-style-type: none;
padding: var(--spacing);
}
.people:empty {
border: var(--border);
}
.people:empty::before {
content: 'No people added.';
}
li {
border: var(--border);
display: flex;
gap: var(--spacing);
padding-block: calc(var(--spacing)/2);
padding-inline: var(--spacing);
}
.delete {
cursor: pointer;
display: inline-block;
overflow: hidden;
position: relative;
width: 1em;
height: 1em;
background-image: url(https://www.davidrhysthomas.co.uk/img/delete.svg);
}
output {
display: grid;
grid-column: span var(--maxColSpan);
place-items: center;
}
output::after {
content: 'per person';
}
output:empty::after {
content: '';
}
@media screen and (max-width: 900px) {
:root {
--numColumns: 1;
--maxColSpan: 1;
--rowHeight: min-content;
}
}
<datalist id="people">
<option>Ana</option>
<option>Carmen</option>
<option>Daniel</option>
<option>Dolores</option>
<option>Josefa</option>
<option>Juan</option>
<option>Luis</option>
<option>Maria</option>
<option>Ramón</option>
</datalist>
<form action="#">
<fieldset>
<label for="names">Names</label>
<input id="name" type="text" name="name" placeholder="Juan, Federico, Ana..." list="people">
<button type="button" >Add person</button>
<label>Total amount to share (€)</label>
<input id="amount" type="number" name="amount" value="0" min="0" step="0.01">
<button type="button" id="calculate">Calculate</button>
</fieldset>
<ul ></ul>
<aside></aside>
<output></output>
</form>
References:
- Array literals (
[...]
). Array.prototype.includes()
.Array.prototype.map()
.- Arrow functions.
document.createElement()
.document.querySelector()
.document.querySelectorAll()
.Element.classList
API.Element.closest()
.Element.matches()
.Element.querySelector()
.Element.querySelectorAll()
.Element.remove()
.Event.currentTarget
.Event.target
.EventTarget.addEventListener()
.isFinite()
.isNaN()
.Number.prototype.toFixed()
.parseFloat()
.- Spread syntax (
...
). String.prototype.trim()
.