Angular, Node.js, and MongoDB: Building a CRUD Application
This article will guide you through building a basic CRUD (Create, Read, Update, Delete) application using Angular, Node.js, and MongoDB. We'll cover the essential steps, from setting up the environment to creating the front-end and back-end functionalities.
Prerequisites
Before we begin, ensure you have the following prerequisites:
- Node.js and npm (or yarn): Download and install Node.js from . This will also include npm, the package manager for Node.js.
- MongoDB: Download and install MongoDB from .
- Basic understanding of Angular, Node.js, and MongoDB: Having some familiarity with these technologies will make it easier to follow along.
Project Setup
-
Create a new Angular project:
ng new my-crud-app cd my-crud-app
-
Create a new Node.js project:
mkdir backend cd backend npm init -y
Backend Development (Node.js and MongoDB)
-
Install dependencies:
npm install express mongoose body-parser cors
-
Create a
server.js
file:const express = require('express'); const mongoose = require('mongoose'); const bodyParser = require('body-parser'); const cors = require('cors'); const app = express(); const port = process.env.PORT || 3000; // Connect to MongoDB mongoose.connect('mongodb://localhost:27017/my-crud-db', { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('Connected to MongoDB')) .catch(err => console.error('Error connecting to MongoDB:', err)); // Middleware app.use(bodyParser.json()); app.use(cors()); // Define the schema for your data const ItemSchema = new mongoose.Schema({ name: { type: String, required: true }, description: String, }); const Item = mongoose.model('Item', ItemSchema); // Define routes app.get('/api/items', async (req, res) => { try { const items = await Item.find(); res.json(items); } catch (err) { res.status(500).json({ error: err.message }); } }); app.post('/api/items', async (req, res) => { try { const newItem = new Item(req.body); await newItem.save(); res.status(201).json(newItem); } catch (err) { res.status(400).json({ error: err.message }); } }); app.put('/api/items/:id', async (req, res) => { try { const updatedItem = await Item.findByIdAndUpdate(req.params.id, req.body, { new: true }); if (!updatedItem) { return res.status(404).json({ error: 'Item not found' }); } res.json(updatedItem); } catch (err) { res.status(400).json({ error: err.message }); } }); app.delete('/api/items/:id', async (req, res) => { try { const deletedItem = await Item.findByIdAndDelete(req.params.id); if (!deletedItem) { return res.status(404).json({ error: 'Item not found' }); } res.json({ message: 'Item deleted successfully' }); } catch (err) { res.status(500).json({ error: err.message }); } }); // Start the server app.listen(port, () => { console.log(`Server listening on port ${port}`); });
Front-End Development (Angular)
-
Install the
@angular/material
package:ng add @angular/material
-
Generate components:
ng generate component item-list ng generate component item-form
-
Modify
app.module.ts
:import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { MatButtonModule } from '@angular/material/button'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatTableModule } from '@angular/material/table'; import { MatIconModule } from '@angular/material/icon'; import { MatDialogModule } from '@angular/material/dialog'; import { AppComponent } from './app.component'; import { ItemListComponent } from './item-list/item-list.component'; import { ItemFormComponent } from './item-form/item-form.component'; @NgModule({ declarations: [ AppComponent, ItemListComponent, ItemFormComponent, ], imports: [ BrowserModule, HttpClientModule, BrowserAnimationsModule, MatButtonModule, MatFormFieldModule, MatInputModule, MatTableModule, MatIconModule, MatDialogModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
-
Implement
item-list.component.ts
:import { Component, OnInit } from '@angular/core'; import { ItemService } from '../services/item.service'; import { MatDialog } from '@angular/material/dialog'; import { ItemFormComponent } from '../item-form/item-form.component'; @Component({ selector: 'app-item-list', templateUrl: './item-list.component.html', styleUrls: ['./item-list.component.css'] }) export class ItemListComponent implements OnInit { items: any[] = []; displayedColumns: string[] = ['name', 'description', 'actions']; constructor(private itemService: ItemService, private dialog: MatDialog) { } ngOnInit(): void { this.getItemList(); } getItemList() { this.itemService.getItems().subscribe( (items: any[]) => { this.items = items; }, (error) => { console.error('Error fetching items:', error); } ); } deleteItem(id: string) { this.itemService.deleteItem(id).subscribe( (response) => { this.getItemList(); }, (error) => { console.error('Error deleting item:', error); } ); } openDialog(item: any = null) { const dialogRef = this.dialog.open(ItemFormComponent, { width: '400px', data: item }); dialogRef.afterClosed().subscribe(result => { if (result) { this.getItemList(); } }); } }
-
Implement
item-list.component.html
:Name {{item.name}} Description {{item.description}} Actions -
Implement
item-form.component.ts
:import { Component, Inject } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { ItemService } from '../services/item.service'; @Component({ selector: 'app-item-form', templateUrl: './item-form.component.html', styleUrls: ['./item-form.component.css'] }) export class ItemFormComponent { item: any = { name: '', description: '' }; constructor( public dialogRef: MatDialogRef
, @Inject(MAT_DIALOG_DATA) public data: any, private itemService: ItemService ) { if (this.data) { this.item = this.data; } } onSubmit() { if (this.item._id) { this.itemService.updateItem(this.item._id, this.item).subscribe( (response) => { this.dialogRef.close(true); }, (error) => { console.error('Error updating item:', error); } ); } else { this.itemService.addItem(this.item).subscribe( (response) => { this.dialogRef.close(true); }, (error) => { console.error('Error adding item:', error); } ); } } onCancel() { this.dialogRef.close(); } } -
Implement
item-form.component.html
: -
Create a
item.service.ts
file:import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ItemService { private apiUrl = 'http://localhost:3000/api/items'; constructor(private http: HttpClient) { } getItems(): Observable
{ return this.http.get (this.apiUrl); } addItem(item: any): Observable { return this.http.post (this.apiUrl, item); } updateItem(id: string, item: any): Observable { return this.http.put (`${this.apiUrl}/${id}`, item); } deleteItem(id: string): Observable { return this.http.delete (`${this.apiUrl}/${id}`); } }
Running the Application
-
Start the backend server:
cd backend node server.js
-
Start the Angular application:
cd .. ng serve
-
Access the application: Open your browser and visit
http://localhost:4200
.
Now, you have a basic CRUD application using Angular, Node.js, and MongoDB. You can add, view, edit, and delete items, and all data is stored in your MongoDB database. You can further enhance this application by adding features like pagination, search, and more complex data structures.