How to render Debugger AJAX Object to screen

Background:

I have successfully been using AJAX for a long time to search a MySqli books database and recently discovered that the server is getting needlessly thrashed because the search activates on every keystroke. Apparently I should be using a JavaScript debounce routine which includes a delay after each key-stroke and only searches after keyboard has finished debouncing.

Search Routine without Keyboard debounce

Wiki Test:

A very simple JavaScript Wiki debounce tutorial was used and works

Wiki Search Routine with debounce

Applying Debounce to the MySqli book database:

The Wiki tutorial was modified and I managed to return the results but only in the Debugger. I was not able to convert the AJAX Object to a HTML string and render the results to the screen.

My Search Routine with debounce

Debugger Screenshot of search “Lee child one shot” results:

Relevant JavaScript that requires modifying:

//=======================================================================
const search = debounce(async (searchTerm) => 
{
    // if the search term is removed, reset the search result
    if (!searchTerm) {
        // reset the search result
        searchResultElem.innerHTML = '';
        return;
    }

    try {
        searchResultElem.innerHTML = '<h3 class="fgR"> SENT FROM AJAX BUT NOT CORRECT BOOK LISTING </h3>';
        // make an API request
        // const url = `https://en.wikipedia.org/w/api.php?action=query&list=search&prop=info|extracts&inprop=url&utf8=&format=json&origin=*&srlimit=10&srsearch=${searchTerm}`;

        const url = 'AJAX-0048.php?q=' + searchTerm;
        const response = await fetch(url);
        console.log(response);
        // const searchResults = await response.json();
        searchResults = await response;

        // SOME FAILED ATTEMPTS TO RENDER RESULTS
        if(0) {
            // alert('searchResults.status ==> ' + searchResults.status);
            // alert(searchResults.transferred);
            // alert(searchResults.version);
            // alert(searchResults.transferred);
            // render search result
            // const searchResultHtml = generateSearchResultHTML(searchResults.query.search, searchTerm);
            // add the search result to the searchResultElem
            // searchResultElem.innerHTML = searchResultHtml;
        }//

    } catch (error) {
        console.log(error);
    }
});

If it is not possible to extract and render the search results I would be grateful for a helpful and simple tutorial.

Hi John,

As your backend is returning HTML, you need to call the .text() method on the response.

i.e. this:

const response = await fetch(url);
searchResults = await response;

becomes:

const response = await fetch(url);
const searchResults = await response.text();

You can drop this into your site (I cannot try it out from here because of CORS) and see if it gives you the desired result:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Ajax Search</title>
  </head>
  <body>
    <input placeholder="Type to Search" />
    <div id="result"></div>

    <script>
      const resultDiv = document.querySelector('#result');

      const delay = (() => {
        let timer = 0;

        return function(callback, ms) {
          clearTimeout(timer);
          timer = setTimeout(callback, ms);
        };
      })();

      document.querySelector('input').addEventListener('keyup', (e) => {
        delay(
          async () => {
            const searchTerm = e.target.value;
            if(!searchTerm) return;

            try {
              const response = await fetch(`https://dasabookcafe.tk/AJAX-0048.php?q=${searchTerm}`);
              const result = await response.text();
              resultDiv.innerHTML = result
            } catch (error) {
              console.error(error);
            }
          },
          500
        );
      });
    </script>
  </body>
</html>

The Ajax request is only fired off when the user has typed nothing for 500 milliseconds.

2 Likes

Hi James,

Many, many, many thanks, .text() worked a treat and only one minor adjustment:

   searchResultElem.innerHTML = result;
   // resultDiv.innerHTML = result

You’ve no idea how long I have been fumbling in the dark and trying different functions :slight_smile: JavaScript is quite involved and adding AJAX takes it way over my head :frowning:

My script drastically requires eliminating all the junk and to make it more readable then… just need to get the relevant book covers, etc

Many thanks once again,

No worries, man. Happy to help :slight_smile:

1 Like

Now the script has been debugged and optimised, I have made some slight changes:

  1. default now ?mode=debounce
  2. added ?mode=allkeys

Hey John,

The debouncing should be taking place on the client (as demonstrated in my code sample). Can I ask why you are passing it as a parameter to the server?

A while ago I was working on a similar transition, where you have both types of states, implement them both in the code, then update the code so that the default state doesn’t need to be specified, and then remove the now unwanted and unneeded state.

I’m hoping that he’s working on a similar transition :slight_smile:

You mean a debounced version and a non-debounced version and that the client is grabbing that info from the query string before deciding which version to implement?

There are over 17,000 books updated from a XLS spreadsheet on an hourly basis and the search routine builds a query string to interrogate the MySQL database then formats and renders the search results.

The debouncing does occur in the browser and only a complete search string is passed instead of searching on every keystroke - causing unnecessary thrashing.

I am open to ideas on how to improve the current setup.

Edit:

I have left the mode parameters in place so SP users can still test and notice the difference. It just means loading a different JavaScript file. As mentioned the default input search is now debounced and not searching on every keystroke.

Sounds good to me, John :slight_smile:

1 Like

I’m curious and just in case I am missing out or have something new to learn… I would be grateful for further details.

If it helps, I was recently working my way through the Second Edition of Refactoring and found that I was able to use some of what it said in the Refactoring API’s part, to achieve a multi-step transition in a very simple way.

A catalog of most of the refactorings is at https://refactoring.com/catalog/, but the book helps flesh out the examples with a more in-depth coverage.

I’ve been able to gain access to the web edition of the book from https://martinfowler.com/articles/access-refactoring-web-edition.html, and recommend that it might be worth your while to take at least one look through the book too.

2 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.