Question

I have a SELECT element in which I need to auto-select the appropriate option based on the first half of a postcode entered in a text field. British postcodes are of the form AB12 3CD, where the first section consists of 1-2 letters representing the county and a number representing the area within the county. The last 3 characters are irrelevant for this question.

For most of the fields it is based on only the first letter(s), but for some options it is a postcode range. The HTML should explain it best:

<select id="country_field">
  <option value="">Select</option>
  <option value="AB">AB (Aberdeen)</option>
  <option value="AL">AL (St. Albans)</option>
  <option value="B">B (Birmingham)</option>
  <option value="BA">BA (Bath)</option>
  ...
  <option value="DD1">DD 1-7 (Dundee)</option>
  <option value="DD8">DD 8-11 (Dundee)</option>
  ...
</select>

My code below will currently select the correct element when the value is exactly two letters. But I need to expand it to encompass the single-letter codes (Birmingham) and the postcode ranges (Dundee). Note: I can change the option values if there is a solution that warrants special values, e.g. DD1/DD2 instead of DD1/DD8.

In short:

  • B2 --> Birmingham
  • BA3 --> Bath
  • DD5 --> first Dundee [DD1]
  • DD11 --> second Dundee [DD8]

Here's the Javascript I have so far...

window.onload = function()
{
  // postcode INPUT field
  var zipInput = document.getElementById( 'zip_field' );
  // county SELECT field
  var ctySelect = document.getElementById( 'county_field' );

  zipInput.onchange = function()
  {
    var zipValue = zipInput.value;
    var ctyOptions = ctySelect.options;
    for ( i = 0; i < ctyOptions.length; i++ )
    {
      if ( zipValue.substring(0,2) == ctyOptions[i].value )
        ctyOptions[i].selected = true;
    }
  }
}
Was it helpful?

Solution

You can use a regular expression to pull out the values...

/^([a-z]{1,2})(\d*)\s/i

Then, for a code with a range like DD, perhaps something like this (pseudo-code)...

if(match[1].value == "DD") {   // needs special processing
  range = match[2].value;
  range = range < 8 ? 1 : 8;   // if the number is less than 8, set it to 1, otherwise set it to 8
  listValue = match[1].value + range
} else                         // just use the letters to select the list item 
  listValue = match[1].value;

So, for DD5, this will return DD1 and for DD11 it will return DD8. Something like B2 or BA3 will simply return B and BA, respectively.

You could change the if to a switch if you have multiple other codes with different ranges. Then, just set the list item with that value as the current selection.

OTHER TIPS

Replace:

zipInput.onchange = function()
  {
    var zipValue = zipInput.value;
    var ctyOptions = ctySelect.options;
    for ( i = 0; i < ctyOptions.length; i++ )
    {
      if ( zipValue.substring(0,2) == ctyOptions[i].value )
        ctyOptions[i].selected = true;
    }
  }

With:

zipInput.onchange = function()
  {
    var zipValue = zipInput.value.match(/^[a-z]+/gi);

    var ctyOptions = ctySelect.options;
    for ( i = 0; i < ctyOptions.length; i++ )
    {
      if (zipValue[0] === ctyOptions[i].value )
        ctyOptions[i].selected = true;
    }
  }
  1. First of all, we removeed the variable assign action from the loop. Why waste cycles repeating the same operation?
  2. Number two, we now filter out everything except the letters in the beginning of the input.
  3. This can in turn be expanded to include the number suffixes, etc.

You can compare the begining of the zipValue with the options values. No need for regular expressions. Just use indexOf.

  zipInput.onchange = function()
  {
    var zipValue = zipInput.value.toUpperCase();
    var ctyOptions = ctySelect.options;
    for ( i = 0; i < ctyOptions.length; i++ )
    {
      if ( zipValue.indexOf(ctyOptions[i].value) == 0 )
        ctyOptions[i].selected = true;
    }
  }

I'm not sure how this would work in javascript but I'd do something like the following:

  • Set up your values to be regular expressions to match what you're looking for

So then, "B", becomes "^B[0-9]" (I'm assuming it must be followed by a number)

BA becomes "^BA[0-9]"

DD1 becomes "^DD([1-7] )"

DD8 becomes "^DD([8-9] |[1][01] )" to match DD8, DD9, DD10, DD11

Then just run the regex against your string (no need to substring it as the ^ makes sure this match occurs at the start of the string) and check if there was a successful match.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top