0

I have two values on my html page, that I got from a form.

The person completes the amount of money they have on one input, and on the other input, the number of people.

So, my question is:

How do i divide the amount.value by the people.value, and distribute it, in a way it appears as shown in the example below?

Amount: 150 / Number of People: 3

-Person 1 - 50
-Person 2 - 50
-Person 3 - 50

What i'm actually struggling with, is to create a function that will add to the HMTL another person + the result, depending on the number of people added previously.

Fadrick
  • 69
  • 8
  • You'll need to store the form input as variables and then perform the calculations and append them to DOM elements you create for that purpose. What's the technical difficulty? – egremont of yorke Apr 15 '22 at 22:52
  • What formula is used to arrive at the percentages? For example, suppose there are 100 people? – Yogi Apr 15 '22 at 23:03

2 Answers2

0

The code down below just finds the total share of all people and distributes the amount among them dependin on their shares.

/*----- Define your variables in here ------*/
    var amount = 150;
    var people = {
        1: 0.75,
        2: 0.15,
        3: 0.10
    }
    var totalSharePerc = 0;

/*----- Loop thruogh people to calculate total sum ------*/
    for (const [key, value] of Object.entries(people)) {
        totalSharePerc = totalSharePerc + value;
    }
    
/*----- Loop thruogh people and split the amount ------*/
    for (const [key, value] of Object.entries(people)) {
        
        /*------ Calculate share of person -----*/
            var share = (amount*value/totalSharePerc);
        
        /*----- Do whatever you want ------*/
            console.log("Person"+key+" => "+share);
        
    }
JamalThaBoss
  • 336
  • 2
  • 7
  • Thanks a lot for answering so quickly, but i realized it wouldn't be viable to make it work with different percentages. I actually updated my question, with something that would actually be better for the original idea. Do you have any idea on how to do that? – Fadrick Apr 16 '22 at 01:48
0

You can use Array#reduce() to calculate the total share for every person involved.

This assumes you have a mapping defined of which person has to cover which share (which you will need to have if you want to distribute in non-equal shares).

const amount = 150;
// define mapping of percentages to persons
const sharesPerPersonPct = {
  1: 0.75,
  2: 0.15,
  3: 0.1,
};

// create a mapping of total values to persons
const sharesPerPersonTotal = Object.entries(sharesPerPersonPct).reduce(
  (allShares, [personId, share]) => {
    allShares[personId] = {
        pct: share,             // add percentage (optional)
        total: amount * share   // add total share
    }
    return allShares;
  },
  {}
);

console.log("Resulting JS object:")
console.log(sharesPerPersonTotal);

Object.entries(sharesPerPersonTotal).forEach(([personId, share]) => console.log(`Person ${personId} has to cover ${(share.pct * 100).toFixed(2)}% which amounts to ${share.total}$.`))

Updated answer to reflect your edit

The following is for an equal distribution of an amount to a number of people. The challenge is that e.g 10$ cannot be distributed 3.33$ for each of 3 persons as then penny would be missing. This is the sort of stuff you get when using floating point arithmetic. To prevent that use integer arithmetic instead. So multiply 10$ by 100 so you get 1000p and you can then assign each person their floored share (Math.floor(1000 / 3) = 333) use modulo to get the remainder (10 % 3 = 1) and distribute that remainder among the persons involved. The current implementation isn't quite fair either though because it always assigns that one penny more starting from the front, but you could use something like this to account for that.

The rest is just input validation using RegEx and displaying the results doing some DOM manipulation.

function handleUpdateDistribution() {
  const amountMoney = document.getElementById("amount-money");
  const noPersons = document.getElementById("no-persons");
  if (!isMoneyValid(amountMoney.value)) {
    console.log("Money value can only have two decimal places!");
    return;
  }
  if (!isNoPersonValid(amountMoney.value)) {
    console.log("Number of persons must be an integer greater than one!");
    return;
  }
  const distribution = updateDistribution(
    Number.parseInt(noPersons.value),
    Number.parseFloat(amountMoney.value)
  );
  showDistribution(distribution);
}

function isMoneyValid(money) {
  const matches = money.match(/^[0-9]+(\.[0-9]{1,2})?$/g);
  if (matches === null) return null;
  else return matches[0];
}

function isNoPersonValid(noPersons) {
  const matches = noPersons.match(/[1-9]*/g);
  if (matches === null) return null;
  else return matches[0];
}

function showDistribution(distribution) {
  const list = document.createElement("ul");
  const listItems = Object.entries(distribution).map(([personId, share]) => {
    const item = document.createElement("li");
    item.textContent = `Person ${personId} has to cover ${share}$.`;
    return item;
  });

  list.append(...listItems);
  document.getElementById("result").replaceChildren(list);
}

/**
 *
 * @param {number} noPersons number of persons to split between
 * @param {number} amountMoney amount of money to split
 */
function updateDistribution(noPersons, amountMoney) {
  // use integer arithmetic as floating point arithmetic is not very suitable for task at hand
  amountMoney *= 100;
  const share = Math.floor(amountMoney / noPersons);
  let remainder = amountMoney % noPersons;
  const persons = {};
  for (let i = 1; i <= noPersons; i++) {
    const shareInInts = share + (remainder > 0 ? 1 : 0);
    remainder--;
    persons[i] = (shareInInts / 100).toFixed(2);
  }
  return persons;
}

window.addEventListener("DOMContentLoaded", (e) => {
  const amountMoney = document.getElementById("amount-money");
  const noPersons = document.getElementById("no-persons");
  amountMoney.addEventListener("input", handleUpdateDistribution);
  noPersons.addEventListener("input", handleUpdateDistribution);
});
input:invalid {
  border: red solid 3px;
}
<form>
  <input id="no-persons" placeholder="Number of persons" type="number" required />
  <input id="amount-money" placeholder="Amount of money" type="text" pattern="^[0-9]+(\.[0-9]{1,2})?$" required />
</form>
<div id="result"></div>

Please note you can and should do more to give the user a nice user experience (Show popovers instead of console.log(), nicer styling etc). See MDN docs on form validation. You should also probably restrict the number of persons as rendering thousands of list items will seriously impact the performance.

Mushroomator
  • 6,516
  • 1
  • 10
  • 27
  • Thanks for the quick response, but i realized it wouldn't be viable to make it work with different percentages. I actually updated my question, with something that would actually be better for the original idea. Do you have any idea on how to do that? – Fadrick Apr 16 '22 at 01:47
  • I've edited my answer to reflect that. – Mushroomator Apr 16 '22 at 11:02