Ajax in Node.js: How to Build a Live Search Feature

Ajax search is a crucial feature in modern web applications, allowing users to quickly find information without reloading the entire page. This tutorial will guide you through creating an Ajax search box using Node.js and MySQL, with Bootstrap and Typeahead.js for the front-end.

Setting Up the Project

First, create a new Node.js project and install the necessary dependencies:

npm init -y
npm install express ejs mysql2 body-parser

Here we’re initialising a new Node.js project with default settings using npm init -y. The -y flag automatically accepts all the default options without asking questions. Then, we’re installing the necessary packages for our project. Express will handle our server routing, EJS will be our template engine, mysql2 will connect to our database, and body-parser will help us process incoming request data.

Update your package.json file:

{
  "name": "ajax-search-node",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.17.1",
    "ejs": "^3.1.6",
    "mysql2": "^2.3.0",
    "body-parser": "^1.19.0"
  }
}

This file contains metadata about our project and lists all the dependencies. The name field identifies our project, and the version tracks our project version. The dependencies section lists all the external packages our project needs to run. The caret (^) before each version number means that npm can install later minor versions if available.

Database Setup

Create a MySQL database and table:

CREATE DATABASE ajax_search;
USE ajax_search;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  first_name VARCHAR(50),
  last_name VARCHAR(50),
  email VARCHAR(100)
);

INSERT INTO users (first_name, last_name, email) VALUES
('John', 'Doe', '[email protected]'),
('Jane', 'Smith', '[email protected]'),
('Alice', 'Johnson', '[email protected]');

In this SQL code, we first create a new database called ajax_search and then switch to using it. Next, we define a users table with four columns: an auto-incrementing ID that serves as the primary key, first name, last name, and email address. The VARCHAR data type specifies text fields with maximum lengths. After creating the table structure, we insert three sample users with their details, which will give us some data to search through when testing our application.

Server-Side Code

Create a file named server.js:

const express = require('express');
const mysql = require('mysql2');
const bodyParser = require('body-parser');
const path = require('path');

const app = express();
const port = 3000;

In the above code, we’re importing the necessary modules for our application. We use the require() function to bring in Express, MySQL, body-parser, and the built-in path module. Then we create an instance of Express and store it in the app variable, which we’ll use to define routes and start our server. We also set the port number to 3000, which is where our server will listen for incoming connections.

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

Here we’re configuring our Express application. We set EJS as our template engine, which will allow us to create dynamic HTML pages. We specify that our view templates are located in the ‘views’ directory. The path.join() function creates a proper file path regardless of the operating system. We also set up the ‘public’ directory to serve static files like CSS, JavaScript, and images. Finally, we configure body-parser middleware to handle both URL-encoded form data and JSON data in incoming requests.

const db = mysql.createConnection({
  host: 'localhost',
  user: 'your_username',
  password: 'your_password',
  database: 'ajax_search'
});

db.connect((err) => {
  if (err) throw err;
  console.log('Connected to MySQL database');
});

This code establishes a connection to our MySQL database. We create a connection object with the database credentials and configuration. The host is set to ‘localhost’ because our database is running on the same machine as our Node.js application. You need to replace ‘your_username’ and ‘your_password’ with your actual MySQL credentials. Then we call the connect() method to establish the connection. If there’s an error, we throw it, otherwise we log a success message to the console.

app.get('/', (req, res) => {
  res.render('index');
});

app.get('/search', (req, res) => {
  const searchTerm = req.query.term;
  const query = `SELECT * FROM users WHERE first_name LIKE ? OR last_name LIKE ? OR email LIKE ?`;
  const params = [`%${searchTerm}%`, `%${searchTerm}%`, `%${searchTerm}%`];

  db.query(query, params, (err, results) => {
    if (err) throw err;
    res.json(results);
  });
});

app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
});

In this section, we define two routes for our application. The first route handles requests to the root URL (‘/’) and renders our ‘index’ template. The second route handles search requests. When a GET request comes to ‘/search’, we extract the search term from the query parameters. Then we create an SQL query that searches for the term in the first name, last name, and email fields. The percent signs (%) are wildcards that match any characters before or after our search term. We use parameterized queries with question marks (?) to prevent SQL injection attacks. We execute the query and send the results back as JSON. Finally, we start our server listening on the specified port and log a message with the URL.

Front-End Code

Create a views folder and add index.ejs:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Ajax Search with Node.js</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/typeaheadjs.min.css">
</head>
<body>
    <div class="container mt-5">
        <h1 class="mb-4">Ajax Search with Node.js</h1>
        <div class="row">
            <div class="col-md-6">
                <input type="text" id="search" class="form-control" placeholder="Search users...">
            </div>
        </div>
        <div class="row mt-3">
            <div class="col-md-6">
                <ul id="results" class="list-group"></ul>
            </div>
        </div>
    </div>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/typeahead.bundle.min.js"></script>
    <script src="/js/main.js"></script>
</body>
</html>

This is our HTML template using EJS. We start with the standard HTML5 document structure and set the language to English. In the head section, we define the character encoding and viewport settings for responsive design. We give our page a title and include the Bootstrap CSS framework for styling and the Typeahead.js CSS for our search suggestions. In the body, we create a container with a heading, a search input field, and an empty list to display results. The Bootstrap classes like ‘container’, ‘mt-5’, and ‘col-md-6’ help with layout and spacing. At the bottom, we include jQuery, Bootstrap’s JavaScript bundle, the Typeahead.js library, and our custom JavaScript file.

Create a public/js folder and add main.js:

$(document).ready(function() {
    var users = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote: {
            url: '/search?term=%QUERY',
            wildcard: '%QUERY'
        }
    });

    $('#search').typeahead(null, {
        name: 'users',
        display: 'first_name',
        source: users,
        templates: {
            empty: '<div class="tt-suggestion">No results found</div>',
            suggestion: function(data) {
                return '<div>' + data.first_name + ' ' + data.last_name + ' (' + data.email + ')</div>';
            }
        }
    });

    $('#search').on('typeahead:select', function(ev, suggestion) {
        $('#results').html('<li class="list-group-item">' + suggestion.first_name + ' ' + suggestion.last_name + ' - ' + suggestion.email + '</li>');
    });
});

In this JavaScript file, we’re setting up our Ajax search functionality. We wrap everything in a jQuery document ready function, which ensures our code runs only after the page is fully loaded. We create a new Bloodhound object, which is Typeahead’s suggestion engine. We configure it to tokenize both our data and the user’s query by whitespace. The ‘remote’ property tells Bloodhound to fetch suggestions from our server, replacing ‘%QUERY’ with the user’s input.

Next, we initialize the Typeahead plugin on our search input. The first parameter (null) is for options, and the second is for dataset configuration. We give our dataset a name, specify which property to display, and set the source to our Bloodhound engine. We also define templates for when there are no results and for how each suggestion should appear.

Finally, we add an event listener for when a user selects a suggestion. When this happens, we update the results list with the selected user’s information. The HTML is wrapped in Bootstrap’s list group classes for nice styling.

Running the Application

1. Start the server: 

node server.js

This command runs our Node.js server. It executes the JavaScript code in our server.js file, which sets up our Express application, connects to the database, defines the routes, and starts listening for incoming connections on port 3000.

2. Open a browser and visit:

http://localhost:3000

By entering this URL in a web browser, you’re making a request to your local machine on port 3000, where your Node.js server is running. The server will respond by rendering the index.ejs template, and you’ll see your Ajax search application in the browser. You can now type in the search box to see it in action.

Conclusion

Now you can create a real-time search box with Ajax in Node.js where users can type in the search field and instantly see matching results without reloading the page. This Ajax-powered search makes the experience smoother by showing results as they type.

Shahid
Shahid

Founder of Codeforgeek. Technologist. Published Author. Engineer. Content Creator. Teaching Everything I learn!

Articles: 128