klas mack klas mack - 1 month ago 6
Javascript Question

Check if input is between two values(multiple conditions)

I am making a project where I need to read in numbers that can be in different format and check these against the users input. In some cases this will be an intervall like "8800-9000", in some cases it will be a 4-digit number, in some cases a 5-digit number.

The array looks like this:

var testArray = [
{
"label": "Nordea",
"value": ["1100-1199", "1400-2099", "3000-3399", "3410-4999"]
},
{
"label": "Swedbank",
"value": ["7000-7120", "7123-8104", "8106-8999"]
},
{
"label": "Sparbanken Nord",
"value": "8264"
},
{
"label": "Sparbanken i Enköping",
"value": ["7121-7122", "8305-5"]
}];


I've made a huge nested if-mess that works kind of OK. My only issue is that its not breaking when it finds a match. If i input "8305-5" it will find a match in 2 different object property arrays. Have I designed the "between"-function wrong?

Also I can search for numbers that are way bigger than the intervalls and still get a match. Intervall "3410 - 3999" is in an array, and if I search for "39999" it will still get a match.

All help much appreciated!

I iterate over all objects in the array, and if the value-property is an array I will check the lenght of each element to see if I should match a "between"-value or a straight "===" match.

If its not an array I try a simple match.

function searchForClearing() {

var userInput = document.getElementById("clearingnummerTextBox").value;

for (var i in testArray) {
var currentObject = testArray[i];

if (Array.isArray(currentObject.value)) {

for (i = 0; i < currentObject.value.length; i++) {

if (currentObject.value[i].length === 9) {

var firstInterval = currentObject.value[i].split('-')[0];

var lastInterval = currentObject.value[i].split('-')[1];

if (userInput >= firstInterval && userInput <= lastInterval) {
console.log("Inmatat: " + userInput + " " + "Träff på: " + currentObject.value);
document.getElementById("bankResult").innerHTML = currentObject.label;
console.log("Sökte mellan intervallen: " + firstInterval + " - " + lastInterval);

console.log("9 teckens sök");
}

} else if (currentObject.value[i].length === 6) {

if (userInput == currentObject.value[i]) {
console.log("Inmatat: " + userInput + " " + "Träff på: " + currentObject.value);
document.getElementById("bankResult").innerHTML = currentObject.label;
console.log("Sökte mellan intervallen: " + firstInterval + " - " + lastInterval);
console.log("6 teckens sök");
}
}
}
} else {
if (currentObject.value.length === 9) {

var firstInterval = currentObject.value.split('-')[0];
var lastInterval = currentObject.value.split('-')[1];

if (userInput >= firstInterval && userInput <= lastInterval) {
console.log("Inmatat: " + userInput + " " + "Träff på: " + currentObject.label);
document.getElementById("bankResult").innerHTML = currentObject.label;
console.log("Sökte mellan intervallen: " + firstInterval + " - " + lastInterval);
return true;
}

} else if (currentObject.value.length === 4) {

if (userInput == currentObject.value) {
console.log("Träff på clearingnummer som inte var i en array: " + userInput + " " + currentObject.label);
document.getElementById("bankResult").innerHTML = currentObject.label;
return true;
}

}

}
}
}

Answer

The reason you have "39999" return true even though its out-of-range is because strings in JS are compared lexographically.

"39999" < "4999" // true
 39999  <  4999  // false

You need to converted the strings to numbers using something like parseInt before doing the comparison.

As far as reducing some of the nested if mess, your two best friends for this example are Array.prototype.find and Array.prototype.some.

Both find and some iterate over an array calling a function for every element.

  • find: If that function returns true, find stops iterating and returns the current element. You can use it to find an object within your testArray whose value is equal to the user input or contains it in a range.

  • some: If that function returns true, some stops iterating and returns true as well. You can use it when the testArray value is an array to check if user input is within at least one of the ranges. We use some instead of another find because we only want to check if something is contained in an array and we don't care to actually get it back.

Here's how you can write your function using find and some:

function findTestObject(input) {

  // iterate over the test array and 
  // stop as soon we found a match 
  // (as the passed function returns true)
  return testArray.find(function (testObj) {
    var value = testObj.value;

    // if current value is an array of ranges
    // check if userInput is within at least one of the ranges
    if (Array.isArray(value)) {
      return value.some(function (range) {
        // split the current range into min and max and compare with user input
        var rangeData = range.split('-');
        return parseInt(rangeData[0]) <= input && input <= parseInt(rangeData[1]);
      });
    } 
    // otherwise do a direct comparison
    else {
      return value === input;
    }
  });
}

This function will either return the first object from testArray whose value matches user input, or undefined.

Here's a full example:

var testArray = [{
  "label": "Nordea",
  "value": ["1100-1199", "1400-2099", "3000-3399", "3410-4999"]
}, {
  "label": "Swedbank",
  "value": ["7000-7120", "7123-8104", "8106-8999"]
}, {
  "label": "Sparbanken Nord",
  "value": "8264"
}, {
  "label": "Sparbanken i Enköping",
  "value": ["7121-7122", "8305-5"]
}];

function findTestObject(input) {
  return testArray.find(function (testObj) {
    var value = testObj.value;

    if (Array.isArray(value)) {
      return value.some(function (range) {
        var rangeData = range.split('-');
        return parseInt(rangeData[0]) <= input && input <= parseInt(rangeData[1]);
      });
    } 
else {
      return value === input;
    }
  });
}

function test() {
  var userInput = document.getElementById("input").value;
  var result = findTestObject(userInput);
  var label = result ? result.label : 'Not Found';
  document.getElementById("result").innerHTML = label;
}
<input id="input" placeholder="Enter something..."/>
<button onclick="test()">Test</button>
<br />
Result: <div id="result"></div>

Note: You have an inconsistency in your example. All the ranges are in increasing order (min, max) except in the last array, where you have "8305-5". With the code above, this range will never return true.

One way you can solve this is to always sort the range array in ascending order before comparing.

var rangeData = range.split('-').sort();

See How to correctly sort array of integers for examples and gotchas.