2

I'm trying to modify jQuery's autocomplete widget to have the input's background color change while the script is searching for suggestions. Here is my attempt (or have a look at my attempt on jsfiddle):

html

<label for="numbers">Numbers: </label>
<input id="numbers" />

javascript

var numbers = [],
    nb = 10000,
    i;

for (i = 0; i < nb; i += 1) {
    numbers.push(i.toString());
}

function color (color) {
    $('#numbers').css({
        background: color
    });
}

$("#numbers").autocomplete({
    source: numbers,
    search: function (event, ui) {
        console.log('search event fired');
        color("red");
    },
    open: function (event, ui) {
        console.log('open event fired');
        color("green");
    },
    close: function (event, ui) {
        console.log('close event fired');
        color("white");
    }
});

As you can see, I'm logging the search, open and close events so I can see when they are fired.

As expected, typing in 5 (an existing value) fires the search event and logs the corresponding message, and, a few seconds later, fires the open event and logs its corresponding message. Since I put 10000 entries in there, there is a noticeable delay between the search event and the open event (something like 1 second).

What baffles me is that when the log message associated to the search event appears, it is not followed by the background color changing to red as should be expected. Instead, it remains white until the open event occurs, then becomes green (as expected after the open event). If, however, I type in a (a non-existing value), the background color goes red without problem (notice the open event never occurs in this case because no corresponding value is found). What's happening here?

For the curious, I'm ultimately trying to have a little loading icon appear while the search is underway (a feature which I am surprised isn't shipped with the widget out of the box). The background color change is a first step in that direction.

UPDATE

I made another attempt which shows that the instruction following console.log is indeed called, but the visual effects appear only much later. Here is the code I'm using:

$("#numbers").autocomplete({
    source: numbers,
    search: function (event, ui) {
        console.log('search event fired');
        $('#numbers').css({
            marginTop: "5em"
        });
        console.log('search callback done');
    }
});

If you try it out, you'll see that both messages are logged before the field is displaced by the addition of a top margin. Somehow, the margin is added at the right time, but the page is not being redrawn at the right time...

Shawn
  • 10,931
  • 18
  • 81
  • 126

2 Answers2

1

So, have you tried this?

$("#numbers").autocomplete({
    source: numbers,
    search: function (event, ui) {
        console.log('search event fired');
        $(this).addClass('working');
    },
    open: function (event, ui) {
        console.log('open event fired');
        color("green");
    },
    close: function (event, ui) {
        console.log('close event fired');
        color("white");
    }
});

That should add a class to your textbox. Just add a CSS style called "working" with background property of red.

Ref. jQuery autocomplete: How to show an animated gif loading image

Community
  • 1
  • 1
user1477388
  • 20,790
  • 32
  • 144
  • 264
  • Really, you shouldn't need any code since the `.ui-autocomplete-loading` class gets applied automatically while the loading is taking place. However, I think there is a bug where it won't show the style. Ref. http://forum.jquery.com/topic/autocomplete-problem-styling-of-ui-autocomplete-loading-not-working – user1477388 Jun 05 '13 at 14:23
  • Yes, I saw that thread, but I never found out how to do the search asynchronously whilst using a static list. There seems to be nothing about it in the documentation... – Shawn Jun 05 '13 at 15:07
  • Sorry I can't help. If you think not being async is the problem, try adding your static values to a server and call them via ajax. – user1477388 Jun 05 '13 at 15:13
  • Looks like it could be paused because javascript is a single-threaded language. They are using a SetTimeout() which pauses the execution... I would try using `source: function(request, response) {` and try to execute your change there before you return the response. – user1477388 Jun 05 '13 at 16:46
  • I am surprised to see the source callback being called on every query. However, it doesn't work either: http://jsfiddle.net/Shawn/VgmE5/ – Shawn Jun 05 '13 at 17:36
  • I think your next best bet is to try playing with the actual jQuery UI method for "search" as shown here http://stackoverflow.com/a/5677466/1477388 It calls a timeout which is what I think is preventing the DOM from being effected by the style. – user1477388 Jun 05 '13 at 17:41
  • I really don't see the relation between that timeout and my problem as all `console.log` works perfectly. – Shawn Jun 05 '13 at 19:21
1

The short answer: it's not your fault :) What's happening, is that the painting of the browsers is basically stalled because of the autocomplete plugin being extemely slow.

To identify how slow and why it's slow, you can use Chrome Devtool's timeline tab. While in frame mode, press record to see a graph like this:

Screenshot of timeline in Devtools

You'll see the yellow bars (Scripts) go way above the bar's outlines once you start entering input. This means the operations cannot be completed in time thus causing the browser to stall. You can view the stacktrace to determine what lines exactly are really slow. The problem is fixable though, but it will require quite some knowledge of the jquery-ui internals.

When working with this many options, frontend scripting may not suffice. You could look into a server-side search with ajax frontend so the heavy lifting is done by the server.

DerLola
  • 3,858
  • 1
  • 19
  • 25
  • Are you saying that the scripting requires so much computing that the browser no longer has "time" to re-draw the screen to the the red background? – Shawn Jun 17 '13 at 22:10
  • Yes. That's because the CSS is done in the 'painting' thread of the browser. Unfortunately, this is also the part of jquery-ui that's slowing down the page. It's stupid and to be honest, I'm surprised jquery-ui isn't written well enough to coop with this. – DerLola Jun 17 '13 at 22:13
  • One more thing, I haven't done a performance comparison, but I've used http://ivaynberg.github.io/select2/#documentation in the past and didn't run into any trouble. Depending on your needs, this might be a good option to look in to. – DerLola Jun 17 '13 at 22:30