Robert Wilde
Robert Wilde

Reputation: 43

Set number input max based on the sum of 4 inputs using jquery

I have 4 input fields and I need the total of all fields not to exceed 100. I want to set the max of the field being changed.

I have been trying to adjust values on keyup() and then difference the total of the other fields from the current and set the max. Seems to work for a bit then stop.

JSfiddle example

var $fieldA = $('#acf-field_55dc6669f5235');
var $fieldB = $('#acf-field_55dc6699f5236');
var $fieldC = $('#acf-field_55dc66d3f5237');
var $fieldD = $('#acf-field_55dc6713f5238');
var total;

function getTotal() {
   total = parseInt($fieldA.val()) + parseInt($fieldB.val()) +      parseInt($fieldC.val()) + parseInt($fieldD.val());
}
$fieldA.change(function () {
   $this = $(this);
   var input = parseInt($this.val());

   var otherFields = parseInt($fieldB.val()) + parseInt($fieldC.val()) + parseInt($fieldD.val());
   var max = 100 - otherFields;

   $this.attr("max", max);
});
$fieldB.change(function () {
   $this = $(this);
   var input = parseInt($this.val());

   var otherFields = parseInt($fieldA.val()) + parseInt($fieldC.val()) + parseInt($fieldD.val());
   var max = 100 - otherFields;

   $this.attr("max", max);
});
$fieldC.keyup(function () {
    $this = $(this);
    var input = parseInt($this.val());

    var otherFields = parseInt($fieldA.val()) + parseInt($fieldB.val()) + parseInt($fieldD.val());
    var max = 100 - otherFields;

    $this.attr("max", max);

});
$fieldD.change(function () {
   $this = $(this);
   var input = parseInt($this.val());

   var otherFields = parseInt($fieldA.val()) + parseInt($fieldB.val()) + parseInt($fieldC.val());
   var max = 100 - otherFields;

   $this.attr("max", max);
});
getTotal;

Upvotes: 4

Views: 2768

Answers (5)

guest271314
guest271314

Reputation: 1

Try utilizing input event , .get() , Array.prototype.map() , Array.prototype.reduce() , Math.max , Array.prototype.sort()


If total values of all input elements is greater than MAX : 100 , decrement value of input that has greatest value in collection of elements ; if event.target with input , change event is element with greatest value , decrement value of element with next greatest value

    var inputs = $("input[id^=acf]"),
        MAX = 100;
    inputs.on("input", function (e) {
        var input = inputs.get(),
            vals = input.map(function (el) {
                return Number(el.value)
            }),
            total = vals.reduce(function (a, b) {
                return a + b
            })
        , el = inputs.sort(function (a, b) {
            return a.value > b.value
        });

        if (total > MAX) {
            $(el).eq($(el[el.length - 1]).is(e.target) 
              ? el.length - 2 
              : el.length - 1)
             .val(function (i, val) {
                return Number(val) - (total % MAX)
            });
        }
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="acf-input-wrap">
  <input id="acf-field_55dc6669f5235" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc6669f5235]" value="30" placeholder="" type="number">
</div>
<div class="acf-input-wrap">
  <input id="acf-field_55dc6699f5236" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc6699f5236]" value="5" placeholder="" type="number">
</div>
<div class="acf-input-wrap">
  <input id="acf-field_55dc66d3f5237" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc66d3f5237]" value="15" placeholder="" type="number">
</div>
<div class="acf-input-wrap">
  <input id="acf-field_55dc6713f5238" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc6713f5238]" value="50" placeholder="" type="number">
</div>

jsfiddle https://jsfiddle.net/q478ujfr/9/

Upvotes: 0

How about just this

$("input[type='number'].acf-is-appended").change(function () {
    $.each($("input[type='number'].acf-is-appended"), function (index, element) {
        var total = 0;
        $.each($("input[type='number'].acf-is-appended").not($(element)), function (innerIndex, innerElement) {
            total += parseInt($(innerElement).val());
        });
        if ($(element).val() > 100 - total) {
            alert("The total value for all inputs can not exceed 100");
            return false;
        } else {
            $(element).attr("max", 100 - total);
        }
    });
});

Fiddle Demo

Upvotes: 1

Wesley Smith
Wesley Smith

Reputation: 19571

This is how I would do it, see comments in code for details:

$('.acf-is-appended').focus(function(){
   $(this).val('');  // clear the current input when it is focused
   var total = 0; // create a var to track the current total
   $('.acf-is-appended').each(function(){  // loop through each element
       total = total + Number($(this).val()); // add the current value to the running total
      $(this).attr('max', Number($(this).val())); // set each element's max to the currently held value
   });
   var remaining = 100 - total; // figure out how much is left before you hit 100
   $(this).attr('max', remaining); // set the max on the current element to match the remaining limit
});

// that will handle the stepper, note that the max wont prevent the user typing in a value higher than the limit
// if you want, you can also make it so typing in a greater value will default to the max value
$('.acf-is-appended').keyup(function(){
    if(Number($(this).val()) > Number($(this).attr('max'))){
        $(this).val($(this).attr('max'))
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="acf-field_55dc6669f5235" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc6669f5235]" value="30" placeholder="" type="number">
</div>
<div class="acf-input-wrap">
  <input id="acf-field_55dc6699f5236" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc6699f5236]" value="5" placeholder="" type="number">
</div>
<div class="acf-input-wrap">
  <input id="acf-field_55dc66d3f5237" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc66d3f5237]" value="15" placeholder="" type="number">
</div>
<div class="acf-input-wrap">
  <input id="acf-field_55dc6713f5238" class="acf-is-appended" min="" max="100" step="any" name="acf[field_55dc6713f5238]" value="50" placeholder="" type="number">
</div>

Upvotes: 2

user2575725
user2575725

Reputation:

Try jQuery input and propertychange handler:

var acfs;

$(function() {
  acfs = $('input[type=text][id^=acf-field_55dc6669f523]'); //cache all once
  acfs.on('input propertychange', checkSum);
});

var max = 100;

var checkSum = function(e) {
  this.value = this.value.replace(/\D/g, ''); //only digits
  var sum = 0;
  var fn = function() {
    sum += +this.value || 0; // parse individual text-box value to int
  };
  acfs.each(fn);
  if (max < sum) // above limit
    this.value = ''; //erase input
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input id='acf-field_55dc6669f5235' type='text' />
<input id='acf-field_55dc6669f5236' type='text' />
<input id='acf-field_55dc6669f5237' type='text' />
<input id='acf-field_55dc6669f5238' type='text' />

Upvotes: 1

Lalji Tadhani
Lalji Tadhani

Reputation: 14149

Change $fieldC.keyup to $fieldC.change

Upvotes: -1

Related Questions