0018abed2b5e8b460993ed915adc0d11

This is a little jQuery script I wrote in order to add a filter field to a selectbox (or multiselectbox). It works fine with few options but is painfully slow with 3000+ options. Any idea to refactor it ?

usage : $("select").multiselect({single: true});

;(function($) {
        $.fn.extend(
            {
                multiselect: function(options) {
                    var options = $.extend({
                            changeCallback: null,
                            single: false,
                        },
                        options || {}
                    );

                    return this.each(function(){
                            $(this).multiselect_render(options);
                        }
                    )
                },
                multiselect_render: function(options) {
                    var $selected_elements = $('<span></span>');

                    var $options = $('<div></div>');

                    var $search = $('<input type="text"/>')
                    .addClass('multiselectSearch')
                    .keyup(function(e) {
                            var _val = $(this).val();

                            if(!_val) {
                                $options
                                .children("div")
                                .show();
                            } else {
                                $options
                                .children("div")
                                .hide()
                                .filter(":icontains("+_val+")")
                                .show();
                            }
                        }
                    );

                    var $widget = $("<div/>") ;

                    var $choose;
                    if(options.single) {
                        $choose = $search
                    } else {
                        $choose = $("<a/>")
                        .addClass('multiselectChoose')
                        .text("[Choose...]");
                    }
                    $choose.click(function(e) {
                            e.preventDefault();
                            $widget.toggle(
                                0,
                                function() {
                                    $(document).click(body_click_hide_widget);
                                }
                            );
                            $search.select();
                        }
                    );

                    var body_click_hide_widget = function(e) {
                        var $$this = $(e.target);

                        if($$this[0] == $choose[0])
                            return;

                        var $$parents = $$this.parents().andSelf();

                        hide = true;
                        for (var i=0; i<$$parents.length; i++) {
                            if($$parents[i] == $widget[0]) {
                                hide=false;
                                break;
                            }
                        }
                        if(hide) {
                            $widget.hide();
                            $(document).unbind("click", body_click_hide_widget);
                        }
                    }

                    var update_selected_elements = function() {
                        var arr = new Array();
                        $options.find(":checked").next('label').each(function() {
                                arr.push($(this).text());
                            }
                        );
                        $selected_elements.text(arr.join(', '));
                    };

                    $widget.append($search);

                    // button close
                    if(!options.single) {
                        $widget
                        .append(
                            $("<a/>")
                            .text("close")
                            .addClass('multiselectClose')
                            .click(function(e) {
                                    e.preventDefault();
                                    $widget.hide();
                                    $(document).unbind("click", body_click_hide_widget);
                                }
                            )
                        )
                    }

                    var $this = $(this).hide();
                    var $opts = $this.children("option");
                    var $parent_id = $this.attr('id');
                    var $parent_name = $this.attr('name');
                    var nb_opts = $opts.length;
                    var type = options.single ? 'radio' : 'checkbox';
                    var opts_arr = new Array();
                    $opts.each(
                        function(idx) {
                            var $$this = $(this);
                            var $$this_value = $$this.val()

                            var input = '<input type="' + type + '" id="' + $parent_id + '-' + $$this_value + '" name="' + $parent_name + '" value="' + $$this_value + '"' + ($$this.is(':selected') ? ' checked=checked' : '') + ' />';

                            var label = '<label for="' + $parent_id + '-' + $$this_value + '">' + $$this.text() + '</label>';

                            var option = '<div>'+input+label+'</div>';

                            opts_arr.push(option);
                        }
                    );

                    $options.append(opts_arr.join(''));

                    $options
                    .children('div').addClass('multiselectOption')
                    .change(
                        function(e) {
                            if(options.changeCallback) {
                                options.changeCallback.call(this);
                            }
                            update_selected_elements();
                            if(options.single) {
                                $search.val($selected_elements.text());
                                $widget.hide();
                                $(document).unbind("click", body_click_hide_widget);
                            }
                        }
                    );

                    update_selected_elements();

                    $widget.append($options);

                    if(options.single) {
                        $choose.val($selected_elements.text())
                        $this.before($choose);
                    } else {
                        $this.before($selected_elements).before($choose);
                    }

                    $this.replaceWith($widget.hide().addClass('multiselectWidget'));
                    return $widget
                }
            }
        );
    }
)(jQuery);

Refactorings

No refactoring yet !

Aacfa176a8d73ca75b90b6375151765a

paul.wilkins.myopenid.com

February 4, 2010, February 04, 2010 02:25, permalink

No rating. Login to rate!

Not to step on your toes, but there'a already a multiselect that has been developed for jQuery UI
http://quasipartikel.at/multiselect/

You may find quite a difference of performance.

1b6e26633e1ebea63c21f126c3da08e0

cna training

February 26, 2010, February 26, 2010 07:54, permalink

No rating. Login to rate!

Keep posting stuff like this i really like it

Your refactoring





Format Copy from initial code

or Cancel