JavaScript large loop logic on keypress

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ShadowLocke
    New Member
    • Jan 2008
    • 116

    JavaScript large loop logic on keypress

    Hi,

    Im trying to use javscript to create somthing similar to an autocomplete control inside of javascript. When typing into an input text it loops through a div of available options and selects the closest match. The problem is i have a case where there is over 1000 possible options. If im looping through 1000 options on every keypress things obviously go a little slow.

    I have taken as many "." lookups out as i can and use a cached length for the loop.

    Any ideas or suggestions?
  • iam_clint
    Recognized Expert Top Contributor
    • Jul 2006
    • 1207

    #2
    first suggestion only start the lookup after 3 characters have been entered...
    so only start the searching say if they type in cat.


    another option place possible search results in an extra div.. so 1 div contains all possible options.. second div contains current matches (less to search through)..

    Limit results

    Comment

    • gits
      Recognized Expert Moderator Expert
      • May 2007
      • 5390

      #3
      additionally it may be, that you could even optimize the loop itself ... show an example of the options and the loop and how this is used to get the matches ...

      kind regards

      Comment

      • ShadowLocke
        New Member
        • Jan 2008
        • 116

        #4
        Originally posted by iam_clint
        first suggestion only start the lookup after 3 characters have been entered...
        so only start the searching say if they type in cat.


        another option place possible search results in an extra div.. so 1 div contains all possible options.. second div contains current matches (less to search through)..

        Limit results
        I like the idea of caching the current matches. Let me explain better what im doing. The idea is to replace the IE select box. With the new select box you would be able to type in and it would use each letter you type in to make a match. (IE currently only brings you to the first match of the letter you type, and if you type a second letter it brings you to the first match of that letter. In FireFox when you type the second letter it keeps the first letter and goes to the first match of first letter plus second letter. {thats hard to explain...})

        Here is the loop that occurs on key up:

        [HTML]function cof_check_match (as_text_id)
        {
        var l_text = document.getEle mentById(as_tex t_id);//Event.element(e vent);
        var l_select = l_text.parentNo de;
        var ls_id = "i_" + l_select.id;
        var l_selectbox = eval(ls_id + ".selectbox ");
        var l_options = eval(ls_id + ".options") ;

        var ls_original = l_text.value;
        var ll_caret = cof_get_caret_p os(l_text)
        var lb_match = false;

        var ll_go_back = 0;

        if( ll_caret > 0)
        ls_original = ls_original.sub string(0, ll_caret);

        var l_option;
        var lb_skip;

        var ls_text_value;
        var ll_text_len;

        ls_text_value = l_text.value.to UpperCase();
        ll_text_len = ls_text_value.l ength;

        while(!lb_match )
        {
        for (var j = 0, jl = l_options.lengt h; j < jl; j++)
        {
        l_option = l_options[j];
        lb_skip = false;

        if(!lb_match)
        {
        var ls_text = l_option.innerH TML.toUpperCase ();

        //See if text is found in list
        if(ls_text.star tsWith(ls_text_ value) && ll_text_len != 0)
        {
        //Open list if its not open
        if (Element.hasCla ssName(l_select , 'hide-dropdown'))
        cof_select_open _dropdown(l_tex t);

        //Scroll to option and set selects value
        l_selectbox.scr ollTop = l_option.offset Top;
        cof_set_select_ value(l_select, l_option);

        //Highlight extra text
        if (l_text.selecti onStart)
        {
        l_text.selectio nStart = ll_text_len;
        l_text.selectio nEnd = l_text.value.le ngth;
        }
        else
        {
        l_txt = l_text.createTe xtRange();
        l_txt.moveStart ("character" , ls_original.len gth - ll_go_back);
        l_txt.moveEnd(" textedit");
        l_txt.select();
        }

        lb_match = true;
        break;
        }
        }
        }

        if(!lb_match && ll_text_len > 0)
        {
        ls_text_value = ls_text_value.s ubstring(0, ll_text_len - 1);
        ll_go_back++;
        }
        else
        ls_text_value = l_text.value.to UpperCase();

        ll_text_len = ls_text_value.l ength;

        if(ll_text_len == 0)
        {
        l_text.value = l_options[0].innerHTML;
        l_text.select() ;
        break;
        }
        }
        }[/HTML]


        I alleviated some of the time by replacing the on key up with this:

        [HTML] var l_text = Event.element(e vent);

        clearTimeout(i_ select_wait);
        i_select_wait = setTimeout("cof _check_match('" + l_text.id + "')", 200);[/HTML]

        Comment

        • gits
          Recognized Expert Moderator Expert
          • May 2007
          • 5390

          #5
          wow ... there's a lot of function calls and dom-operations just for finding matches in a wordlist? function calls and dom-operations are very expensive ones and in case you have much data then this is very bad for performance and even could lead to a message from the browser, that the script could last too long ... i would redesign this code in the following way:

          1. on page-load or when loading the options you could create a javascript-object that correspond to this list that should look like this:

          [CODE=javascript]var list_obj = {
          'OPTION_VALUE_O R_INNER_HTML' : option_referenc e,
          ...
          };[/CODE]
          2. now you could easyly loop through that obj:

          [CODE=javascript]
          // create a regExp that ignores case
          var re = new RegExp('^' + 'your_chars_tha t_should_match' , 'i');

          // this array could store all the matching options
          var matches = [];

          // just one efficient loop to get the matching options
          for (var i in list_obj) {
          if (re.test(i)) {
          matches.push(li st_obj[i]);
          }
          }
          [/CODE]
          3. now just work with the matches-array to build up the dropdownlist

          i assume that you just wanted to show the matching options?

          kind regards

          Comment

          • ShadowLocke
            New Member
            • Jan 2008
            • 116

            #6
            Thanks for taking the time to reply!

            I'm not very experienced with regular expressions (or programming for that matter..) so i tend to forget about them. But i suspect it would be faster than using the toUpperCase & startsWith functions. I actually only want it to return the first ordered match. I was able to speed up a great deal when i changed the way "cof_set_select _value" (not shown) worked as it was looping through the list to unhighlight everything then highlight the selected value. By keeping track of the last item slected i was able to narrow everything down to only the one loop above so now its at least functional. Im gonna rewrite the loop using a regex and see if I can shorten it, then ill post my full results..

            Comment

            • gits
              Recognized Expert Moderator Expert
              • May 2007
              • 5390

              #7
              the greater performance-boost would come from the shown javascript-object that would represent your word-list so that you just wouldn't need to always retrieve the words from the document ...

              kind regards

              Comment

              Working...