4
\$\begingroup\$

I am new to JavaScript, HTML and CSS, although not to programming.

I wanted to style 'select' dropdowns, so I wrote this:

What noob mistakes am I making? Is this a good or evil use of JS?

<head>
<link href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<!--
<link href="./font-awesome-4.0.3/css/font-awesome.css" rel="stylesheet">
-->

<style>
body { font-family: sans-serif; }

.control { display: none; }
.dropdown > dl { margin: 4px; font-family: sans-serif; }
.dropdown > dl > dt { display:inline-block; width: auto; }
.dropdown .value { display: none; }
.dropdown > dl > dd { position: absolute; left: 0; top: 27px; display: none; }

.dropdown > dl { display:inline-block; width: auto; position: relative; cursor: pointer; }
.dropdown > dl > dt { border: 1px solid #ddd; background-color: #eee; color: black; padding: 3px 6px; font-weight: bold; }
.dropdown > dl > dd { border: 1px solid #ddd; background-color: white; margin:0;}
.dropdown > dl > dd > ul { padding:0; margin:0 }
.dropdown > dl > dd > ul > li { list-style: none; padding:5px 10px; padding-left: 28px; }
.dropdown > dl > dt:hover,
.dropdown > dl > dd > ul > li:hover { background-color: #333; color: white; }
.dropdown > dl > dd > ul > li { display: none; }
.dropdown li.selected:before { font-family: 'FontAwesome'; content: '\f00c'; margin: 0 5px 0 -22px; font-weight: normal; }
.dropdown li.selected { font-weight: bold; }
</style>

<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
<!--
<script src="jquery-2.0.3.js"></script>
-->

<script>
    function Dropdown(name) {
        this.name = name;
        this.$root = $('#dropdown').clone().removeAttr('id').show();
        this.$root.children('dl').css('z-index', Dropdown.zindex.next());
        Controls.registerControl(this);

        this.$selected = this.$root.find('dt');
        this.$selectedContents = {
            $text: this.$selected.children('span.text'), 
            $value: this.$selected.children('span.value') };
        this.$popup = this.$root.find('dd');
        this.$options = this.$popup.children('ul');
        this.$option = this.$options.children('li');
        this.$optionContents = { 
            $text: this.$option.children('span.text'), 
            $value: this.$option.children('span.value') };

        var that = this;
        this.$selected.click(function(event) {
            if (!that.$popup.is(':visible')) {
                Controls.blurAll();
            }
            that.$popup.toggle();
        });
        this.$options.click(function(event) {
            that._selectOption($(event.target).is('li') ? $(event.target) : $(event.target).parent('li'));
            that.$popup.hide();
        });
    }
    Dropdown.prototype = {
        constructor: Dropdown,

        _makeOption: function(text, value) {
            this.$optionContents.$text.text(text);
            this.$optionContents.$value.text(value);
            return this.$option.clone();
        },

        setOptions: function(optionsMap) {
            for (var value in optionsMap) {
                var text = optionsMap[value];
                this._makeOption(text, value).appendTo(this.$options).show();
            }
            return this;
        },

        _selectOption: function($option) {
            var text = $option.children('span.text').text();
            var value = $option.children('span.value').text();

            this.$selectedContents.$text.text(text);
            this.$selectedContents.$value.text(value);

            this.$options.children('.selected').removeClass('selected');
            $option.addClass('selected');

            this.$root.closest('form').find('[name="'+this.name+'"]').val(value);
        },

        selectOption: function(value) {
            var that = this;
            this.$options.find('li').each(function (idx, li) {
                if ($(li).find('span.value').text() == value) {
                    that._selectOption($(li));
                }
            });
            return this;
        },

        blur: function() {
            this.$popup.hide();
        }
    };
    Dropdown.replaceSelect = function($select) {
        var options = {};
        $select.children('option').each(function (idx, el) {
            options[$(el).val()] = $(el).text();
        });
        $select.hide().before(
            new Dropdown($select.prop('name'))
                .setOptions(options)
                .selectOption($select.children('option:selected').val())
                .$root);
    };
    Dropdown.replaceSelectByName = function(name) {
        Dropdown.replaceSelect($('select[name="' + name + '"]'));
    };
    Dropdown.replaceAllSelects = function() {
        $('select').each(function (idx, el) {
            Dropdown.replaceSelect($(el));
        });
    };
    Dropdown.zindex = {
        _idx: 100,
        next: function() { return this._idx--; }
    };

    Controls = {
        _controls: [],
        registerControl: function (control) {
            this._controls.push(control);
        },
        blurAll: function () {
            $.each(this._controls, function (idx, control) {
                control.blur();
            });
        }
    }
</script>

</head>

<body>
<form method="POST" action="http://www.htmlcodetutorial.com/cgi-bin/mycgi.pl">
<p>Naci en el mes de <select name="month">
    <option selected value=1>enero</option>
    <option value=2>febrero</option>
    <option value=3>marzo</option>
    <option value=4>avril</option>
    <option value=5>mayo</option>
    <option value=6>junio</option>
    <option value=7>julio</option>
    <option value=8>agosto</option>
    <option value=9>septiembre</option>
    <option value=10>octubre</option>
    <option value=11>noviembre</option>
    <option value=12>diciembre</option></select></p>
<p>Me gusta las <select name="fruit">
    <option value=1>manzanas</option>
    <option selected value=2>peras</option>
    <option value=3>naranjas</option></select></p>
<input type="submit" name="Submit" value="Submit">
</form>

<span class="control dropdown" id="dropdown">
<dl>
    <dt><span class="text"></span><span class="value"></span>&nbsp;<i class="fa fa-caret-down"></i></dt>
    <dd><ul>
        <li><span class="text"></span><span class="value"></span></li>
    </ul></dd>
</dl>
</span>
</body>

<script>
$(document).ready(function () {
    Dropdown.replaceAllSelects();
});
</script>
\$\endgroup\$
  • \$\begingroup\$ Do I conclude that no-one knows if this is good or evil, or that it was so evil (or good) that it left everyone speechless? \$\endgroup\$ – user2886246 Dec 24 '13 at 12:30
  • 1
    \$\begingroup\$ Be assured that we are quick to point out evil. However, if it is difficult to find constuctive criticism (i.e. what is posted is too good or too complex/specific) that can definitely silence the masses. \$\endgroup\$ – Daniel Dec 27 '13 at 14:06
  • 1
    \$\begingroup\$ For this kind of question, you should use jsfiddle.net \$\endgroup\$ – sinsedrix Dec 27 '13 at 16:53
  • 1
    \$\begingroup\$ I use jQuery-selectbox plugin to style select dropdowns, you may have a look at this code. \$\endgroup\$ – sinsedrix Dec 27 '13 at 16:55
  • \$\begingroup\$ Thanks for the tips and links. All useful and taken on board. \$\endgroup\$ – user2886246 Jan 24 '14 at 9:34
2
\$\begingroup\$

Tip for your code:

  • Use $name for var names that represent a jQuery selection, nor for a member (it is the convention).
  • Since you use jQuery, consider writing a plugin extending jQuery.fn instead of prototyping
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ You couldn't have his code working? Weird. jsfiddle.net/sciencepharaoh/JwXPc \$\endgroup\$ – Daniel Dec 27 '13 at 14:04
  • \$\begingroup\$ How did you get it to work @DanielCook ??? \$\endgroup\$ – Malachi Dec 27 '13 at 14:28
  • \$\begingroup\$ @Malachi I put it in JSFiddle? Is it not working? I'm confused. It looks like it works to me. Though my linked fiddle removed some of the options but it worked with them in there as well. Actually, I did add 1 unnecessary semi-colon to make JSHint happy... \$\endgroup\$ – Daniel Dec 27 '13 at 14:43
  • \$\begingroup\$ @DanielCook, I tried to take the code from the original question post, and it was a plain drop down menu. I am probably making noob mistakes myself \$\endgroup\$ – Malachi Dec 27 '13 at 15:41
  • \$\begingroup\$ @Sinsedrix, the tip for your code section is the only section that is actually a review in my opinion \$\endgroup\$ – Malachi Dec 27 '13 at 16:04

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.