C. Gill
C. Gill

Reputation: 175

Using Jquery how to take Input value to determine select box value on Data Min Max Range

I would like to use jQuery on change of the value in an input box using the Data-Min and Data-Max values of my Select options to determine which one to set the Select value to.

I have the following code (Note: I updated options code with static values, options and data values will be loaded dynamically from the database, so they will vary):

<input type="number" step="0.1" name="cbd" id="cbd" class="form-control" onchange="selectGrade()" value="0">

<select class="form-control" name="cbdGrade" id="cbdGrade"> 
<option value=""></option>  
<option value="{D6C3B40F-9559-473A-8B24-44A911A82D52}" data-min="0" data-max="0">CBD 0 - 5.75</option>              
<option value="{4FD86F65-74BA-4F10-9D5F-57281ECFC76A}" data-min="0.1" data-max="1.9">CBD 1 - 17.50</option>
<option value="{3AC0F33C-D48E-4C10-B64A-B5473AF8DB98}" data-min="2" data-max="2.9">CBD 2 - 15.15</option>
</select>

When the end user inputs a value into cbd field I would like to take that value and determine what cbdGrade should be applied. This needs to be accomplished using the data-min and data-max values of the select options. The value input into cbd needs to be within the range. The option with the correct range that the cbd field value fits within should be set as the cbdGrade.

How can I accomplish this? I have some jQuery experience but this one has me stumped on how to get the ranges from each option.

Edit - Adding my script so far.

function selectGrade() {
var cbdLevel = document.getElementById('cbd').value;
var arrGrade = new Array;

$("#cbdGrade option").each  ( function() {
    arrGrade.push ( $(this).data('min')+'-'+$(this).data('max')+'-'+$(this).val());
});

alert ( arrGrade.join(',' ) );

}

This is returning an array of Data and option values, is this the correct way to do this? How do I then iterate through this array and compare it to my variable cbdLevel?

Upvotes: 2

Views: 549

Answers (2)

zer00ne
zer00ne

Reputation: 44078

Event Handling

The following demo upon triggering the "input" event*, on the <input type="number"> will change the <select> <option> according to the value of <input type="number"> being within a dynamic range. Although the demo has hard-coded values for data-min and data-max, the callback function cbd() can handle any valid values set dynamically for each data-min/max pair assigned to each <option>.

* (the advantage of "input" event over "change" event is that it is happens instantly)

BTW never use an on-event attribute:

👎 Example of what NOT to do for event handling with jQuery or JavaScript

<button onclick="functionName()">LAME</button>
...
function functionName(event) {...

When using jQuery, always use the proper method (ex. .click()) or delegate events with the .on() method (I highly recommend using the latter 99% of the time.)

👍 Example of the most effective way of event handling with jQuery

<button class='btn'>NOT LAME</button>
 ...
 $('.btn').on('click', functionName)
 function functionName(event) {...

The demo is commented extensively and there are references provided as well.

Demo

// Delegate input#cdbData to the input event -- callback is cdb()
$(function() {
  $('#cbdData').on('input', cbd);
});

// Callback function/Event handler passes Event Object by default
function cbd(event) {

  /*
  Dereferenced jQuery Object $('#cbdRate') to DOM Object 
  
  NOTE: Plain JavaScript equivelant would be:
  
  const select = document.getElementById('cdbRate');
  or
  const select = document.querySelector('#cdbRate');
  */
  const select = $('#cbdRate')[0];
  // Collect all select#cdbRate option into an Array
  const rates = [...select.options];

  /*
  Store the value of input#cdbData as a real Number in a variable
  IMPORTANT NOTE: input#cdbData is $(this)
  */
  let float = parseFloat($(this).val());
  /*
  Ensure that integer values are suffixed with ".0"
  (this is just for aesthetics and is not required)
  */
  $(this).val(float.toFixed(1));

  /*
  IF input#cdbData value is :out-of-range...
  add .out class and remove .in class
  OTHERWISE...
  do vice versa of the above actions
  (this is just for aesthetics and is not required)
  */
  if ($(this).is(':out-of-range')) {
    $(this).addClass('out').removeClass('in');
  } else {
    $(this).addClass('in').removeClass('out');
  }

  /*
  .flatMap() method (a combo of .map() and .flat() methods), will run a 
  function over each element within a given array and will return a flattened
  array of results. NOTE: the callback function returns an Array of an Array --
  so the final return will be an Array of Arrays 
  (aka two dimensional array, aka data-table)

  On each select#cdbRate option...
  Get the value of data-min convert it into a real Number and add it to the
  minMax sub-Array[0]
  Then do likewise for data-max and minMax sub-Array[1]
  Final returned minMax Array has the following pattern:
  
  minMax = [['', ''], [data-min, data-max], [data-min, data-max], [data-min, data-max]];
    
  Each sub-Array represents the min/max values of an <option>
  Use the .data() jQuery method to set/get data-* attributes
  */
  let minMax = rates.flatMap((opt, idx) => {
    return idx === 0 ? [
      ["", ""]
    ] : [
      [Number($(opt).data('min')), Number($(opt).data('max'))]
    ]
  });

  // Get length of minMax Array
  let size = minMax.length;
  // Get the least and the greatest values of minMax Array
  let min = minMax[1][0];
  let max = minMax[size - 1][1];
  // Assign min and max values to input#cbdData
  this.min = min;
  this.max = max;

  /*
  Iterate through rates Array...
  IF `float` is greater OR equal to current value of minMax sub-Array[0]
  AND...
  IF `float` is less OR equal to current value of minMax sub-Array[1]...
  then select the current <option> 
   
  OR IF `float` is not a Number OR `float` is greater than the last value of 
  minMax Array[1]...
  then select <option> at index 0
  
  IMPORTANT NOTE: The dereferenced jQuery Object `select` must be used because
  the Plain JavaScript property .selectedIndex and .selected are not recognized 
  by jQuery
  */
  for (let [index, option] of rates.entries()) {
    if (float >= minMax[index][0] && float <= minMax[index][1]) {
      option.selected = true;
    } else if (Number.isNaN(float) || float > max) {
      select.selectedIndex = 0;
    }
  }

  // Uncomment the comment below to review the log of minMax Array
  // log(minMax);
  // Stop event bubbling and terminate function
  return false;
}

// Optional utility function (not required)
function log(data) {
  return console.log(JSON.stringify(data));
}
:root {
  font: 400 3vw/6vh Consolas
}

.form-control {
  display: inline-block;
  font: inherit;
  font-size: 1rem
}

#cbdData {
  width: 6ch;
  text-align: center;
}

.in {
  background: initial;
}

.out {
  background: tomato;
}
<input id="cbdData" name="cbdData" class="form-control" type="number" step="0.1">

<select id="cbdRate" name="cbdRate" class="form-control">
  <option value="" default>-----</option>
  <option data-min="0.0" data-max="0.0" value='{D6C3B40F-9559-473A-8B24-44A911A82D52}'>CBD 0</option>
  <option data-min="0.1" data-max="1.9" value='{4FD86F65-74BA-4F10-9D5F-57281ECFC76A}'>CBD 1</option>
  <option data-min="2.0" data-max="2.9" value='{3AC0F33C-D48E-4C10-B64A-B5473AF8DB98}'>CBD 2</option>
</select>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


References

Delegating events with jQuery .on() method

Dereferencing jQuery Object to DOM Object

Creating or cloning an array via spread operator

$(this)

.flatMap()

Destructuring arrays with .entries() and a for...of loop

.selectedIndex and .selected properties and .options HTML Collection

Upvotes: 1

Christian Carrillo
Christian Carrillo

Reputation: 2761

u can try:

function selectGrade(value) {
      const valueNumber = Number(value)
      switch (true) {
        case valueNumber < 0:
          cbdGrade.selectedIndex = 0
          break;
        case valueNumber === 0:
          cbdGrade.selectedIndex = 1
          break;
        case valueNumber <= 1.9:
          cbdGrade.selectedIndex = 2
          break;
        case valueNumber <= 2.9:
          cbdGrade.selectedIndex = 3
          break;
        default:
          cbdGrade.selectedIndex = 0
          break;
      }
    }
<input type="number" step="0.1" name="cbd" id="cbd" class="form-control" onchange="selectGrade(this.value)" value="0">

<select class="form-control" name="cbdGrade" id="cbdGrade">
  <option value=""></option>
  <option value="{D6C3B40F-9559-473A-8B24-44A911A82D52}" data-min="0" data-max="0">CBD 0 - 5.75</option>
  <option value="{4FD86F65-74BA-4F10-9D5F-57281ECFC76A}" data-min="0.1" data-max="1.9">CBD 1 - 17.50</option>
  <option value="{3AC0F33C-D48E-4C10-B64A-B5473AF8DB98}" data-min="2" data-max="2.9">CBD 2 - 15.15</option>
</select>

Upvotes: 0

Related Questions