4
\$\begingroup\$

I've got a code that is working in my environment. Nevertheless it is pretty ugly.

This is what I am trying to do. I get a selectbox from a side with a lot of city names. I filter some names and push them into an array and hide them. The other ones are also pushed into an array, but shown.

Now I append two options to the end of the selectbox, one is displayed, the other one hidden.

When someone clicks the option all, the options from the array otherCities are shown and defaultCities are hidden. the option all is hidden as well, less is shown.

This behavior works the other way round, too.

How can I simplify my code? Any help is welcome.

var otherCities = new Array();
var defaultCities = new Array();
var selectBoxCity = jQuery("select[name='city']");  

if(selectBoxCity.size() != 0) {
        selectBoxCity.prepend('<option value="" selected="selected">-- Please Select --</option>');
    otherCities = new Array();
    defaultCities = new Array();
    var cityArray = ['OE', 'MK', 'SI', 'BO', 'DO', 'BM', 'HER', 'GE', 'HH'];
    var options = jQuery("select[name='city'] option");
    options.each(function() {
        var o = jQuery(this);
        if (jQuery.inArray(o.attr("value"), cityArray) == -1) { 
            otherCities.push(o.hide());
        } else {
            defaultCities.push(o.show());
        }
    });
    selectBoxCity.find("option").end().append("<option value='all'>+</option>");
    selectBoxCity.find("option").end().append("<option value='less'>-</option>");

}


var selectBoxCity = jQuery("select[name='city']");
selectBoxCity.find("option:first").attr("selected", true);

$("select[name='city'] option[value='less']").hide();

if(selectBoxCity.val() == "all") {
    jQuery.each(otherCities,function() {
        $(this).show();
    });
    jQuery.each(defaultCities,function() {
        $(this).hide();
    }); 
    $("select[name='city'] option[value='all']").hide();
    $("select[name='city'] option[value='less']").show();
}
if(selectBoxCity.val() == "less") {
    jQuery.each(otherCities,function() {
        $(this).hide();
    });
    jQuery.each(defaultCities,function() {
        $(this).show();
    }); 
    $("select[name='city'] option[value='all']").show();
    $("select[name='city'] option[value='less']").hide();
}
\$\endgroup\$
  • 1
    \$\begingroup\$ I suggest throwing your code at JSLint, and thinking about its suggestions. \$\endgroup\$ – ANeves Oct 10 '12 at 15:20
  • \$\begingroup\$ Thanks for the hint. The markup is OK. I was asking about the functions. Whether I could simplify them. \$\endgroup\$ – user1735221 Oct 10 '12 at 16:20
  • 1
    \$\begingroup\$ It'd be better to have the default cities marked in the markup (e.g. give them a class like default). Then you only need to run some selectors to hide/show, and won't have duplication of city values in your JS. Probably, also a good idea to keep the "please select" option in the markup rather than prepending it \$\endgroup\$ – Flambino Oct 10 '12 at 16:21
  • \$\begingroup\$ By the way, hiding/showing an option tag doesn't seem to have any effect here in Chrome \$\endgroup\$ – Flambino Oct 10 '12 at 16:36
  • \$\begingroup\$ Hi, I have no influence on the actual markup. I'm just manipulating it via jQuery. The code works fine here. I've just sent the snippets I wasn't sure about the simplicity, so it may not work in your environment. \$\endgroup\$ – user1735221 Oct 10 '12 at 16:47
2
\$\begingroup\$

Here's something that seems to work OK (here's a demo)

jQuery(function ($) {
  var select   = $("select[name=city]"),
      defaults = select.children(".default"),
      others   = select.children(":not(.default)");

  others.remove();

  select.on("change", function (event) {
    var value = select.val();
    if(value === "more") {
      defaults.remove();
      select.append(others);
    } else if(value === "less") {
      others.remove();
      select.append(defaults);
    }
  });
});​

Everything else is stored in the markup, like so:

<select name="city">
  <!-- default options -->
  <option class="default">A</option>
  <option class="default">B</option>
  <option class="default">C</option>
  <option value="more" class="default">Show more</option>

  <!-- expanded options -->
  <option>D</option>
  <option>E</option>
  <option>F</option>
  <option>G</option>
  <option>H</option>
  <option>I</option>
  <option value="less">Show less</option>
</select>​

As I said in the comments, .hide and .show doesn't seem to have any effect on <option> elements. Neither does visibility: hidden. In either case, they all show up in the select dropdown. You can disable options, but then they're still there, just greyed out.
Hence, this code forcibly removes/appends the options.

Of course, it might make more sense to simply remove/append only the non-default options. To me it makes more sense that the default options are a subset of all the options, not an entirely different set of options.

Furthermore, it might be good to let the more/less options be added by JS, so clients that don't support JS don't see them.

Putting all that together, you get this.
Without JS, you'll just see a full list. With JS, you get the more/less options and all that jazz.

\$\endgroup\$
  • \$\begingroup\$ I know it's tricky, but the options A,B,C shouldn't be shown when selecting more :-) \$\endgroup\$ – user1735221 Oct 10 '12 at 17:09
  • \$\begingroup\$ Which is what the code here does. It's only the 2nd jsfiddle demo that keeps the defaults around when selecting "more" \$\endgroup\$ – Flambino Oct 10 '12 at 17:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.