Reputation: 175
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
Reputation: 44078
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:
<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.)
<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.
// 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>
Delegating events with jQuery .on()
method
Dereferencing jQuery Object to DOM Object
Creating or cloning an array via spread operator
Destructuring arrays with .entries()
and a for...of
loop
.selectedIndex
and .selected
properties and .options
HTML Collection
Upvotes: 1
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