0

We have a web application that shows a lot of (big) tables. For a user friendly UI we have implemented search (filter) as you type using ajax and loading partial views.

In short:

  1. input control tbSearch with a listener for the keyup event:
.on('keyup', 'input.filter', function () {
    showList(this);
}
  1. showList() fetches a _PartialView from the Controller and then loads the filtered result in the div/table (section-list):
function showList(control) {
    
    // search text
    var searchString = $('#tbSearch').val();

    // url
    var url = 'mycontroller/myaction';

    //parameters
    var data = {
        searchString: searchString,
    };

    $('.section-list').load(url, data, function () {
        
    });
}

So far pretty basic partialview loading with ajax. And it works great most of the times.

There is a problem when a user types quickly and the query to search the database is a bit more complex. In such cases (since ajax.load is async) the showList() function can be triggered for a new searchstring before the previous search has even loaded. This can then result for the results of the actual keyword entered by the user to be overridden by one of the previous keywords.

Example, I start writing quickly into the searchbox:

  • m
  • my
  • mys
  • myse
  • mysea
  • mysearc
  • mysearch (STOP typing)

and instead of results showing data filtered to "mysearch" they can actually be for "mysea".

I was thinking of putting ajax get partialview code into a separate async function (that returns a Promise), add a counter (count keyups on the page) and wait for the ajax function to complete and if the counter matches the last request, separately load the inner html of the div... But this seems like a complex solution.

Any ideas (for a simpler solution)?

TheMixy
  • 1,049
  • 15
  • 36
  • Hi @TheMixy, Try to use the [input event](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event) or the [change event](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/change_event) to get the entered value. – Zhi Lv Feb 22 '21 at 05:24
  • Hi @Zhi Lv. The entered value is not the problem. I'm reading it via the `keyup` event just fine. The problem is the order of showing the results - because ajax is working async. – TheMixy Feb 22 '21 at 08:18
  • Hi @TheMixy, According to your code, I have created a sample using the keyup event, as you said, if types quickly, the event might be not triggered immediately. So, in my previous reply, I suggest you could try to use the input or change event. For the Ajax function, you could consider setting [the `async` property](https://api.jquery.com/jquery.ajax/) to `false`, then, it will send request synchronous. – Zhi Lv Feb 23 '21 at 10:16
  • I was considering setting async to false, but I believe this would negatively influence user experience – TheMixy Feb 23 '21 at 19:17
  • Yes, you are right, using the sync method might be influence user experience. I also search some similar threads such as: [Thread 1](https://stackoverflow.com/questions/42314838/) [Thread 2](https://stackoverflow.com/questions/34513082/) and [Thread 3](https://stackoverflow.com/questions/1620602/).Some people will try to add a timer in the keyup event, after the last typed, wait a moment and then calling the Ajax method. But, most of people will try to use the input or change event. So, you could consider using them. – Zhi Lv Feb 24 '21 at 06:43

1 Answers1

0

I managed to find a solution to keep the "search as you type" functionality with adding and checking against a counter and loading ajax result a bit differently:

//counter
var searchCounter = 0;

function showList(control) {
    // counter 
    searchCounter++;
    var localCounter = searchCounter;

    // search text
    var searchString = $('#tbSearch').val();

    // url
    var url = 'mycontroller/myaction';

    //parameters
    var data = {
        searchString: searchString,
    };

    // ajax load partialview
    $.ajax({
        url: url,
        type: "POST",
        dataType: "html",
        data: data,
        success: function (partialViewHtml) {
            //only load, if counter is still a match
            if (localCounter === searchCounter) {
                $(".section-list").empty().append(partialViewHtml);
               
            }
        }
    });
}
TheMixy
  • 1,049
  • 15
  • 36