Jquery Listbox / Textbox filter

2019-08-25 05:13发布

问题:

I have the following jquery function for filtering the contents of a listbox on the onkeyup event from a textbox.

function DoListBoxFilter(listBoxSelector, filter, keys, values) {
    var list = $(listBoxSelector);
    var selectBase = '<option value="{0}">{1}</option>';

    list.empty();
    for (i = 0; i < values.length; ++i) { //add elements from cache if they match filter

        var value = values[i];

        if (value == "" || value.toLowerCase().indexOf(filter.toLowerCase()) >= 0) {
            var temp = String.format(selectBase, keys[i], value);
            list.append(temp);
        }
    }
}

It works great for small to medium size lists, but it is a little bit slow when working with lists over 300-400 items... Can anyone help with some ideas to optimize the javascript a little bit to speed up the function?

The function is invoked with the following code:

    $('#<% = txtSearch.ClientID %>').keyup(function() {

        var filter = $(this).val();

        DoListBoxFilter('#<% = lstPars.ClientID %>', filter, keys_<% = this.ClientID %>, values_<% = this.ClientID %>);
    });

To use this, I bind an asp.net listbox and also populate two javascript arrays (key and value) on the page.

This IS storing the data in two places on the page, but using this method I am able to use the postback of the listbox to get the selected value without using javacript to extract the value and cache it in a hidden div. (it also saves having to run the function at page load on the clients browser.. and that is really the function where I am seeing the slowness, so storing in two places speeds up the page rendering)

I found that I needed to use the javascript array approach because most browsers don't acknowledge any attempts to hide an option tag... only Firefox appears to do it.

I'm not sure its possible to optimize and speed this code up any more, but if anyone has any ideas I would appreciate it.

Thanks, Max Schilling

回答1:

It looks like you might be suffering in terms of performance with large lists because you are appending each item one at a time that matches the filter. I would build up an array of matches (or create a documentFragment) and then append that to the DOM in one go.

function DoListBoxFilter(listBoxSelector, filter, keys, values) {
    var list = $(listBoxSelector);
    var selectBase = '<option value="{0}">{1}</option>';

    list.empty();
    var i = values.length;
    var temp = [];
    var option, value;
    while (i--) {    
        value = values[i];    
        if (value && value.toLowerCase().indexOf(filter.toLowerCase()) !== -1) {
                option = String.format(selectBase, keys[i], value);
                temp.push(option);
        }
    }
    // we got all the options, now append to DOM
    list.append(temp.join(''));  
}


回答2:

I am also using the same code to filter the list box but with a bit of change, in my code first I am comparing the searched value/word with the option items and if match got success then only filtering the list.

var existText = values[i].substring(0, filter.length);

if (existText.toLowerCase() == filter.toLowerCase())

Below is the full code:

function DoListBoxFilter(listBoxSelector, filter, keys, values) {

  var list = $(listBoxSelector);
  var selectBase = '<option value="{0}">{1}</option>';

  list.empty();
  for (i = 0; i < values.length; ++i) {

    var existText = values[i].substring(0, filter.length);

    if (existText.toLowerCase() == filter.toLowerCase()) {

        var value = values[i];
        if (value === "" || value.toLowerCase().indexOf(filter.toLowerCase()) >= 0) {
            var temp = '<option value="' + keys[i] + '">' + value + '</option>';
            list.append(temp);
        }
    }
  }    
 }

var keys = [];
var values = [];

var options = $('#CountryList option');
$.each(options, function (index, item) {
  keys.push(item.value);
  values.push(item.innerHTML);
});

$(document).ready(function () {
  $('input#CountrySearch').on('keyup', function () {
    var filter = $(this).val();
    DoListBoxFilter('#CountryList', filter, keys, values);
  });
});

You can also see a demo here. In this demo I have used a list containing the more than 500 list items and its working fine without any performance issue.



回答3:

Following link helped me, though it is javascript.

Search ListBox items using JavaScript

<head id="Head1" runat="server">
    <title>Demo</title>
</head>

<script type="text/javascript" language="javascript"> 

    function SearchList()
    {
        var l =  document.getElementById('<%= ListBox1.ClientID %>');
        var tb = document.getElementById('<%= TextBox1.ClientID %>');
        if(tb.value == ""){
            ClearSelection(l);
        }
        else{
            for (var i=0; i < l.options.length; i++){
                if (l.options[i].value.toLowerCase().match(tb.value.toLowerCase()))
                {
                    l.options[i].selected = true;
                    return false;
                }
                else
                {
                    ClearSelection(l);
                }
            }
        }
    }

    function ClearSelection(lb){
        lb.selectedIndex = -1;
    }

</script>
<body> 
    <form id="form1" runat="server">
    <asp:TextBox ID="TextBox1" runat="server" onkeyup="return SearchList();"/><br />
    <asp:ListBox ID="ListBox1" runat="server" Height="150px" Width="250px">
    <asp:ListItem>Vincent</asp:ListItem>
    <asp:ListItem>Jennifer</asp:ListItem>
    <asp:ListItem>Shynne</asp:ListItem>
    <asp:ListItem>Christian</asp:ListItem>
    <asp:ListItem>Helen</asp:ListItem>
    <asp:ListItem>Vladi</asp:ListItem>
    <asp:ListItem>Bee</asp:ListItem>
    <asp:ListItem>Jerome</asp:ListItem>
    <asp:ListItem>Vinz</asp:ListItem>
    <asp:ListItem>Churchill</asp:ListItem>
    <asp:ListItem>Rod</asp:ListItem>
    <asp:ListItem>Mark</asp:ListItem>
    </asp:ListBox>
    </form>
</body>
</html>