Home > Net >  How can I make a function divide the total money by the total of names entered on the button?
How can I make a function divide the total money by the total of names entered on the button?

Time:06-06

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 (&euro;)</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>

JS Fiddle demo

References:

  • Related