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.
will try this out
Nice work man.
Can I send a questyion if i face any problem?
Comments and questions are always welcome ….
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?
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.
This post is actually outdated. Ajax calls can be made very easily with many open JS frameworks.