How to Build a Dynamic Web App Using AJAX, Node.js, Express, and MongoDB

Modern web users expect applications to respond instantly—without jarring page reloads or delays. If you want to build fast, reactive web applications, mastering asynchronous data communication is a must. In this comprehensive, step-by-step tutorial, you will learn how to build a dynamic web app using AJAX, Node.js, Express, and MongoDB.

We will guide you through creating a full-stack application from scratch using a clean, modular project architecture. You will discover how to connect your Node.js backend to MongoDB via Mongoose models, configure Express routers for asynchronous GET, POST, and DELETE operations, and manipulate the DOM dynamically on the frontend using jQuery AJAX—all without a single page refresh.

Project Directory Structure

Organize your project files cleanly using the following modular structure:

ajax/
├── models/
│   └── task.js
├── public/
│   └── data.js
├── routes/
│   └── taskroute.js
├── views/
│   └── demo.ejs
├── app.js
└── package.json
  

Step 1: Initialize the Project and Install Dependencies

Open your command prompt or terminal and set up your working directory:

# Create and move into your project folder

mkdir ajax

cd ajax

# Initialize your Node.js project environment

npm init -y

This creates a package.json file indicating that Node is initialized in the folder.

Next, install all the required backend and frontend packages in a single command:

npm install body-parser express ejs mongoose jquery

Step 2: Create the Mongoose Data Model (models/task.js)

Create a folder named models, add a file named task.js, and define your database schema along with custom static methods for adding, retrieving, and deleting tasks:


var mongoose = require('mongoose');

var taskSchema = new mongoose.Schema({
    task:{
        type:String
    }
});

var taskModel =  module.exports = mongoose.model('task',taskSchema);

module.exports.addTask = (task,cb)=>{
    task.save((err,taskData)=>{
            if(err){
                cb(err,null);
            }else{
                cb(null,taskData);
            }
    });
}

module.exports.getTask = (cb)=>{
    taskModel.find((err,taskData)=>{
          if(err){
              cb(err,null);
          }else{
              cb(null,taskData);
          }
    });
}

module.exports.removeTask = (id,cb)=>{
    taskModel.deleteOne({'_id':id},(err,taskData)=>{
            if(err){
                cb(err,null);
            }else{
                cb(null,taskData);
            }
    });
}  

Step 3: Set Up Express Router (routes/taskroute.js)

Create a folder named routes, add a file named taskroute.js, and handle your HTTP endpoints (GET, POST, and DELETE):

var express    = require('express');
var taskModel  = require('../models/task');

var router = express.Router();

router.get('/home',(req,res)=>{
 res.render('demo');
});


router.post('/addtask',(req,res)=>{
          var taskk = new taskModel({
              task:req.body.task
          });
          taskModel.addTask(taskk,(err,taskData)=>{
              if(err){
                  res.json({msg:'error'});
              }else{
                  res.json({msg:'success'});
              }
          });
});

router.get('/gettask',(req,res)=>{
  taskModel.getTask((err,taskData)=>{
          if(err){
              res.json({msg:'error'});
          }else{
              res.json({msg:'success',data:taskData});
          }
  });
});

router.delete('/removetask',(req,res)=>{
      taskModel.removeTask(req.body.id,(err,taskData)=>{
            if(err){
                res.json({msg:'error'});
            }else{
                res.json({msg:'success'});
            }
      });
});

module.exports = router;  

Step 4: Create the Frontend View (views/demo.ejs)

Create a folder named views, add a file named demo.ejs, and set up the user interface using Bootstrap styling:
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
    <script src="/jquery/jquery.js"></script>
</head>
<body>
    <div class="container" style="margin-top: 50px;">
        <div class="nav justify-content-center">
            <div class="card">
                <h5 class="card-header text-center">ToDo List</h5>
                <div class="card-body">
                    <div class="form-group text-center">
                        <label for="Task">Enter The Task</label>
                        <input type="text" class="form-control" name="Task" id="task" required>
                      </div>
                     <div class="text-center"><button class="btn btn-lg btn-success addbtn">Add Task</button></div> 
                </div>
              </div>
        </div><br>
    <div class="nav justify-content-center tblData" style="overflow-y:scroll; height: 200px;">

        <table class="table table-hover">
            <thead>
            <tr>
                <th>
                    s.no
                </th>
                <th>
                    Task
                </th>
                <th>
                    delete
                </th>
            </tr>
        </thead>
        <tbody >
        </tbody>
        </table>
    </div>
</div>
    <script src="/data.js"></script>
</body>
</html>
  

Step 5: Implement Client-Side AJAX (public/data.js)

Create a folder named public, add a file named data.js, and write your client-side jQuery AJAX code to handle adding, listing, and deleting tasks dynamically:

$(document).ready(function(){
    alert('application started');

    getdata();

    $('.addbtn').click(function(){
         var task = $("#task").val();
       $.ajax({
           url:'/task/addtask',
           method:'post',
           dataType:'json',
           data:{'task':task},
           success:function(response){
               if(response.msg=='success'){
            //    $("#task").remove();
               alert('task added successfully');
               getdata();
               $('#task').val('')
               }else{
                   alert('some error occurred try again');
               }
           },
           error:function(response){
               alert('server error occured')
           }
       });
    });
    $(document).on('click','button.del',function(){
        var id = $(this).parent().find('button.del').val();
        // alert('delte',id)
        $.ajax({
            url:'/task/removetask',
            method:'delete',
            dataType:'json',
            data:{'id':id},
            success:function(response){
                if(response.msg=='success'){
                    alert('data deleted');
                    getdata();
                }else{
                    alert('data not get deleted');
                }
            },
            error:function(response){
                     alert('server error')   
            }
        });
    });
    function getdata(){
        $.ajax({
            url:'/task/gettask',
            method:'get',
            dataType:'json',
            success:function(response){
                 if(response.msg=='success'){
                     $('tr.taskrow').remove()
                     if(response.data==undefined || response.data==null || response.data==''){
                         $('.tblData').hide();
                     }else{
                        $('.tblData').show();
                     $.each(response.data,function(index,data){
                         var url = url+data._id;
                         index+=1;
            $('tbody').append("<tr class='taskrow'><td>"+ index +"</td><td>"+data.task+"</td><td>"+"<button class='del' value='"+data._id+"'>delete</button>"+"</td></tr>"); 
                     });
                 }
               }
            },
            error:function(response){
                alert('server error');
            }
        });
    }
});
  

Step 6: Configure the Entry Point (app.js)

Create your main entry point file named app.js in your root directory:

var express     = require('express');
var mongoose    = require('mongoose');
var bodyParser  = require('body-parser');
var path        = require('path');
var $           = require('jquery');

//connect to db
mongoose.connect('mongodb://localhost:27017/ajaxdemo',{useNewUrlParser:true})
.then(()=>console.log('connected to db'))
.catch((err)=>console.log('connection error',err))

//init app
var app = express();

//set the template engine
app.set('view engine','ejs');

//fetch data from the request
app.use(bodyParser.urlencoded({extended:false}));

//set the path of the jquery file to be used from the node_module jquery package
app.use('/jquery',express.static(path.join(__dirname+'/node_modules/jquery/dist/')));

//set static folder(public) path
app.use(express.static(path.join(__dirname+'/public')));

//default page load
app.get('/',(req,res)=>{
  res.redirect('/task/home');
});

//routes
app.use('/task',require('./routes/taskroute'));

//assign port
var port  = process.env.PORT || 3000;
app.listen(port,()=>console.log('server run at port '+port));

Open your package.json file and under "scripts" add your start script:

"scripts": {

  "start": "node app.js"

}

Resources

SourceCode : Download the code from here

Video Tutorial : Watch Video Tutorial

Comments

Popular posts from this blog

How to Setup a Flask Project in Python: Step-by-Step Guide

How to Use Sequelize-CLI to Create Tables and Relationships in Node.js

How to Upload Images in Node.js and Express Using AJAX and jQuery