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

Javascript

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
;(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