0

Often a search filter is not hitting a simple local database, but rather a remote server thousands of kilometres away. In addition, if the dataset is of a non-trivial size, then processing the query and returning the results to the client also has a delay. Maybe a search component may also have a small forced delay to increase perceived value or complexity in producing the results. There may also be a debounce in there so we're not hammering the backend with every key stroke.

Let's say I'm looking for Foo Bar Car Rental. I type in the query:

Search: foo Searching...

A spinner or some kind of activity UX is a great way of indicating the initial round-trip, so the client can signal the user that results are on their way. The results come back:

Search: foo

Results (5):

  • Football results
  • Foo alpha ipsum
  • Foo bad
  • Foo Bar Car Rental
  • Foo Bar Star

A glance of the first and second results in the list shows that I'm not quite there, so type in in 'bar' to my search query to narrow it down a bit. But hang on! The fourth result is what I'm looking for! I start pressing the down arrow, and have pressed it twice already, and will press it twice more to hit my desired result:

Search: foo bar Searching...

Results (5):

  • Football results
  • Foo alpha ipsum
  • Foo bad
  • Foo Bar Car Rental
  • Foo Bar Star

I need to press the down arrow twice more, and then press return, but suddenly all of the delays of the debounce, server filtering, and server response have finally occurred. In my experience, I will be quickly pressing those buttons before I realise the change in search results.

Here's what usually happens in this situation. The user selection completely resets with the new results. This means that no item is highlighted. I may be pressing the keys faster than I realise the change in search results, and I will wind up being shuttled off to the wrong place (from before, Down x2, Return x1):

Search: foo bar

Results (2):

  • Foo Bar Car Rental
  • Foo Bar Star

If I have begun pressing the down arrow or moved the mouse of a particular result, then surely this should be a signal to the search component that I have found or am finding the desired. If the search results list is particularly long (the amazon.com search return is currently 10 results, for example), then I may be in the process of arrowing down to my intended result when the search component resets my progress with a fresh list.

This is a particular problem when bandwidth is constrained and latency is increased, as the round-trip between client and server is prolonged and the user has more time to realise and signal that a desired result has been found. You can simulate the impact of this using browser dev tools, such as the GPRS setting in Chrome, for example.

I have seen this issue so many times in search filtering, but perhaps it means I should just be a little more patient? For me, if the user has signalled that they have found something relevant by pressing an arrow or moving their mouse through search terms, the user is provided with a short debounce before moving on to the new list.

Basically, the old results should remain in place until the user has shown a disinterest in the old results.

The bit what I am not sure about is the experience of signalling new results are available... perhaps by a notification in the search bar like below? There could be some kind of progress bar indication that resets each time the user presses the down button, for example.

What do you think?

Search: foo bar New Results!

Results (5):

  • Football results
  • Foo alpha ipsum
  • Foo bad
  • Foo Bar Car Rental
  • Foo Bar Star

Interestingly, when using the stackoverflow tag searching when going to post this question, it has a variation of the proposed UX which is partially welcomed but also partially annoying. If I find a search result while the round-trip is occurring, the updated search results are completely voided. If I determine the result is not what I was looking for, I need to arrow up to the search input, press backspace, and then type the character I removed to continue with my search.

1

I would suggest two things to avoid this.

  1. Don't search for anything unless the user's input is at least 3 characters long. This avoids hitting the server for a useless search. Of course this depends on whether you do actually have results shorter than 3 letters.
  2. You need a two level search to avoid the behavior. The two cache levels being 1 ) a cache of current results and 2) the server. Just so we understand each other the logic should be (in javascript).

First let's mock the server

//Mocking the server results
var server = ["spray", "sprint", "sponge", "limit", "elite", "exuberant", "destruction", "present"];

//Mocking a function that queries the server.
function searchFromServer(keyword){
    console.log("server hit");
    return server.filter(function(res){
        return res.startsWith(keyword);
    });
}

Then here's your client side code.

//You're going to need a cache.
var cache = [];

function search(keyword){

    //1. Search only if the input is at least 3 chars long.
    if(keyword.length > 2){
        console.log("======Searching for '%s'...", keyword)
        //2. First search whether the keyword matches anything in the cached results.
        var results = [];
        results = searchCache(keyword);
        console.log("Results in cache %o", results);

        //If there are no results in the cache, then search in the server.
        if(!results.length>0){
            console.log("No hits in cache.");
            cache = searchFromServer(keyword);
            results = cache;
        }
        console.log("Cache: %o", cache);
        console.log("Results: %o", results);
        return results;
    }
    else{
        console.log("=======Won't search for as little as '%s'", keyword);
    }
}

//Search the cached results.
function searchCache(keyword){
    console.log("Cache: " + cache);
    return cache.filter(function(res) {
        return res.startsWith(keyword);
    });
}

Then to test it:

search("sp");
search("spr");
search("spra");
search("lim");

Then, just bind the result of the search(keyword) function to your list of elements.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.