Ajax Autocomplete Tutorial

This tutorial was originally written in 2008 around Ajax Agent, a PHP/JavaScript micro-framework that has since disappeared — and its server code rode on the old mysql_* functions, which were removed in PHP 7.0. The idea underneath it (type-ahead search against a server endpoint, without a full page reload) is more useful than ever, so here is the same artist/album/track example rebuilt with the platform as it stands today: PDO with prepared statements on the server, and fetch() plus the native <datalist> element on the client. No framework required.

Part 1: A JSON search endpoint

The original example embedded a SQL query inside a PHP function and concatenated the user’s input straight into the query string — a textbook SQL injection hole. The modern version binds the parameter and returns JSON instead of HTML fragments:

<?php
// search.php — type-ahead artist lookup
header('Content-Type: application/json');

$term = $_GET['q'] ?? '';
if (mb_strlen($term) < 2) {
    echo json_encode([]);
    exit;
}

$db = new PDO(
    'mysql:host=localhost;dbname=music;charset=utf8mb4',
    'dbUser',
    'dbPwd',
    [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);

$stmt = $db->prepare(
    'SELECT artist_name FROM artists
     WHERE artist_name LIKE :prefix
     ORDER BY artist_name
     LIMIT 10'
);
$stmt->execute([':prefix' => $term . '%']);

echo json_encode($stmt->fetchAll(PDO::FETCH_COLUMN));

Two details worth keeping even in a small endpoint: the LIMIT clause (never ship an unbounded autocomplete query) and the length guard that skips the database entirely for one-character input.

Part 2: Autocomplete in the browser

The 2008 version hacked together a hidden <select> box, hand-rolled onkeyup wiring, and a custom RPC layer. Today the browser gives you the dropdown for free with <datalist>:

<label for="artistName">Artist</label>
<input id="artistName" list="matches" autocomplete="off">
<datalist id="matches"></datalist>

The script below uses fetch() with two refinements the original lacked: a debounce so we do not fire a request per keystroke, and an AbortController so a slow earlier request cannot overwrite a newer one’s results:

const input = document.getElementById('artistName');
const matches = document.getElementById('matches');
let controller = null;
let timer = null;

input.addEventListener('input', () => {
  clearTimeout(timer);
  timer = setTimeout(async () => {
    const q = input.value.trim();
    if (controller) controller.abort();
    if (q.length < 2) { matches.innerHTML = ''; return; }

    controller = new AbortController();
    const res = await fetch(`search.php?q=${encodeURIComponent(q)}`, {
      signal: controller.signal,
    });
    const names = await res.json();
    matches.innerHTML = names
      .map(name => `<option value="${name}">`)
      .join('');
  }, 200);
});

Because the options are injected as HTML, escape any value that could contain quotes — a JSON-encoded response run through textContent or a proper escaping helper keeps artist names like A&R from breaking the markup. <datalist> also gives you keyboard navigation and screen-reader semantics for free, which the hidden-select trick never did.

Part 3: On your own

The original left the drill-down (artists → albums → tracks) as an exercise, and it is still a good one. The pattern is identical at every level: a second endpoint (albums.php?artist=...) that returns JSON, then a change listener on the input that fetches and renders the result into a plain list. One <ul>, one fetch(), one render function — no page reload, no plugin.

If you are maintaining a codebase that still contains the original Ajax Agent code: the framework is dead, the mysql_* extension is gone, and the query construction is injectable. Port it — the whole thing above is about sixty lines.

5 thoughts on “Ajax Autocomplete Tutorial

  1. ndukuiyu kamau says:

    will try this out
    Nice work man.

    Can I send a questyion if i face any problem?

    Reply
  2. Rhymnnaizenia says:

    Hi. I repeatedly announce this forum. This is the head culture unqualified to ask a query.
    How numberless in this forum are references progressive behind, disingenuous users?
    Can I bank all the facts that there is?

    Reply
  3. Justin says:

    Hello. Where do I download agent.php? Also, I do not see a link for the source code. This looks like a great tutorial and I would like to complete it but I cannot without the code.

    Thanks.

    Reply
    1. teliaz says:

      This post is actually outdated. Ajax calls can be made very easily with many open JS frameworks.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *