How to change values ​​by changing one of them using javascript?

There are three fields with numbers from 1 to 3. I try to make sure that if a person uses only arrows, there should always be one "1", one "2" and one "3". Why does this not always work and how can I make it work?

jQuery(document).ready(function($) {
  var prevNumber;
  $(".numbers").focus(function() {
    prevNumber = $(this).val();
  }).change(function() {
    curNumber = $(this).val();
    $('.numbers[value="' + curNumber + '"]:not(:focus)').first().val(prevNumber);
    prevNumber = curNumber;
  });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Run codeHide result

Here is the jsfiddle .

+4
source share
4 answers

Why does this approach not work

The attribute is valuenot connected to an input value. I know this sounds amazing. :-) The attribute valueis the default value for input. It does not change (unless you use setAttribute("value", x);or .defaultValue = x;to change it).

:

$('.numbers[value="' + curNumber + '"]')...

, , , , , .

, , defaultValue, value ( defaultValue , ), (. ):

jQuery(document).ready(function($) {
  var prevNumber;
  $(".numbers").focus(function() {
    prevNumber = $(this).val();
  }).change(function() {
    // Get the element wrapper
    var $this = $(this);
    
    // Get the current value
    var curNumber = $this.val();
    
    // Make sure the default value on this element is updated
    this.defaultValue = curNumber;
    
    // Update both the value and default value on the other
    // input that used to have this number
    $('.numbers[value="' + curNumber + '"]:not(:focus)').first().val(prevNumber).prop("defaultValue", prevNumber);
    prevNumber = curNumber;
  });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Hide result

( - )

, , , , change: , . . :

var numbers = $(".numbers").map(function() { return this.value; }).get();
jQuery(document).ready(function($) {
  $(".numbers").change(function() {
    // Get a wrapper for this input
    var $this = $(this);
    // Get this number
    var thisNumber = $this.val();
    // Get the unused numbers
    var unused = numbers.filter(function(num) { return num != thisNumber; });
    // Assign them to the siblings, in order
    $this.siblings().val(function(index) {
      return unused[index];
    });
  });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Hide result

, , , 1, 2 3 ( , ).

+6

, "value" initial . :

$('.numbers[value="' + curNumber + '"]:not(:focus)')

, , . , :

$('.numbers:not(:focus)').filter(function(index, element){ 
    return $(element).val() == curNumber; 
  })

jsfiddle.;)

+2

, : JS <input />, ( , <input> . , , DOM, ( : ).

Given your problem (the values ​​should be unique and only swaps should be accessible), it’s easier to deal with it as a pure JS problem (and don't try to do everything in jQuery - although I agree with it in a large library, it is not necessarily the best tool for everything )

Here is my commented solution:

jQuery(document).ready(function($) {

  // This array the current values of the inputs
  var numbers = [1, 2, 3];

  // numbers should not be modified directly but trough
  // setNumber: this function ensures that numbers is ALWAYS
  // a swap of the original value ([1, 2, 3]).
  // When a value is set, this function returns the previous
  // index of the value
  function setNumber(index, newVal) {
    // find other index
    var prevIndex = numbers.indexOf(newVal);
    if (prevIndex < 0) {
      alert('Invalid value, please enter 1, 2 or 3');
    }
    // swap
    numbers[prevIndex] = numbers[index];
    numbers[index] = newVal;
    return prevIndex;
  }

  // This function updates the inputs to ensure
  // that their displayed value match the one stored in numbers
  function updateNumbersView() {
    $(".numbers").each(function(idx, elem) {
      elem = $(elem);
      if (parseInt(elem.val(), 10) !== numbers[idx]) {
        elem.val(numbers[idx]);
      }
    });
  }

  $(".numbers").change(function() {
    var self = $(this);
    var curNumber = parseInt(self.val(), 10);
    var curIndex = $(".numbers").index(self);
    if (curNumber === numbers[curIndex]) {
      return false; // no change
    }
    
    // update model:
    var changedIndex = setNumber(curIndex, curNumber);
    
    // updateView:
    $('.numbers').eq(changedIndex).val(numbers[changedIndex]);
    
    // or to be more generic (ie. multiple inputs for the same value):
    // updateNumbersView();
    
  });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
Run codeHide result
+1
source

I would solve this by adding another property to each node.

jQuery(document).ready(function($) {
    var $numbers = $('.numbers'),
        off = false;
    $numbers.each(function () {
        this.prev = this.value;
    });
    $numbers.change(function () {
        var source = this;
        if (off) return; // this algorithm is already running
        off = true;
        $numbers.each(function () {
            if (this !== source && this.value === source.value) { // if conflict
                this.prev = this.value = source.prev; // swap with old value
            }
        });
        this.prev = this.value; // update for next time
        off = false; // re-enable
    });
});
<input type="number" value="1" min="1" max="3" step="1" class="numbers" />
<input type="number" value="2" min="1" max="3" step="1" class="numbers" />
<input type="number" value="3" min="1" max="3" step="1" class="numbers" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Run codeHide result
+1
source

Source: https://habr.com/ru/post/1625996/


All Articles