javascriptlogic

Balance value of three input fields to always sum up to 100


I would like to balance a user input of three input fields so that they will always sum up 100.

The initial state is: 100, 0, 0, when the user enters let's say 50 in the second input, it should become: 50, 50, 0. I am doing this in Vue but technically it is irrelevant for the question. I have tried:

adjustPercentage(changedValue) {
  if (changedValue === 'input1') {
    this.input2 = 100 - this.input1 - this.input3;
    this.input3 = 100 - this.input1 - this.input2;
  } else if (changedValue === 'input2') {
    this.input1 = 100 - this.input2 - this.input3;
    this.input3 = 100 - this.input1 - this.input2;
  } else if (changedValue === 'input3') {
    this.input1 = 100 - this.input2 - this.input3;
    this.input2 = 100 - this.input1 - this.input3;
  }

  // Ensure the values are clamped to avoid negative percentages
  if (this.input1 < 0) this.input1 = 0;
  if (this.input2 < 0) this.input2 = 0;
  if (this.input3 < 0) this.input3 = 0;
},

But I cannot get it to work properly, if I enter let's say a value in input 3 it is exceeding the total sum of 100.


Solution

  • Adjusting < 0 to 0 after you're calculating the other fields will cause the calulation to fail.

    You'll need to set < 0 to 0 before the next input calculation.


    Here an example with a helper function that we call after each line of your existing logics, this could ofc be improved.

    const input1 = document.querySelector('input[name=input1]');
    const input2 = document.querySelector('input[name=input2]');
    const input3 = document.querySelector('input[name=input3]');
    
    const noBelowZero = (input) => (input.value < 0) ? input.value = 0 : {};
    
    const adjust = (event) => {
    
        let name = event.target.name;
    
        if (name === 'input1') {
          input2.value = 100 - input1.value - input3.value; noBelowZero(input2);
          input3.value = 100 - input1.value - input2.value; noBelowZero(input3)
        } else if (name === 'input2') {
          input1.value = 100 - input2.value - input3.value; noBelowZero(input1)
          input3.value = 100 - input1.value - input2.value; noBelowZero(input3)
        } else if (name === 'input3') {
          input1.value = 100 - input2.value - input3.value; noBelowZero(input1)
          input2.value = 100 - input1.value - input3.value; noBelowZero(input2)
        }
    }
    
    [ input1, input2, input3 ].forEach(i => i.addEventListener('change', adjust));
    <input name='input1' value=100 />
    <input name='input2' value=0 />
    <input name='input3' value=0 />