javascriptregexhtml-selectpostal-code

Auto-selection of <option> based on input field, with some caveats


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:

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;
    }
  }
}

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.