CRUD sederhana javascript dan html
Kita akan membuatkan contoh website sederhana menggunakan MySQL, Node.js, dan HTML. Website ini akan memiliki fungsi dasar CRUD (Create, Read, Update, Delete).
buat file
package.json
{
"name": "simple-crud-app",
"version": "1.0.0",
"description": "Simple CRUD application with Node.js and MySQL",
"main": "server.js",
"dependencies": {
"express": "^4.17.1",
"cors": "^2.8.5",
"mysql2": "^2.3.0",
"body-parser": "^1.19.0"
}
}
server.js
const express = require('express');
const mysql = require('mysql2');
const bodyParser = require('body-parser');
const path = require('path');
const cors = require('cors');
const app = express();
// Middleware
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public')));
// Database configuration
const dbConfig = {
host: 'localhost',
user: 'root',
password: '',
database: 'crud'
};
// Create MySQL connection pool instead of single connection
const pool = mysql.createPool(dbConfig);
// Test database connection
pool.getConnection((err, connection) => {
if (err) {
console.error('Error connecting to MySQL database:');
console.error('Error code:', err.code);
console.error('Error message:', err.message);
return;
}
console.log('Successfully connected to MySQL database');
// Release the connection
connection.release();
// Test query
pool.query('SELECT 1 + 1 AS solution', (err, results) => {
if (err) {
console.error('Error executing test query:', err);
return;
}
console.log('Database connection test successful');
});
});
// Middleware to handle database errors
const handleDatabaseError = (err, res) => {
console.error('Database Error:', err);
res.status(500).json({
error: 'Database error occurred',
details: err.message,
code: err.code
});
};
// API Routes
// GET all users
app.get('/api/users', (req, res) => {
console.log('GET /api/users - Fetching all users');
pool.query('SELECT * FROM users ORDER BY id DESC', (err, results) => {
if (err) {
handleDatabaseError(err, res);
return;
}
console.log(`Successfully retrieved ${results.length} users`);
res.json(results);
});
});
// POST new user
app.post('/api/users', (req, res) => {
console.log('POST /api/users - Creating new user:', req.body);
const { name, email } = req.body;
// Input validation
if (!name || !email) {
console.log('Invalid input - Missing required fields');
return res.status(400).json({
error: 'Invalid input',
message: 'Name and email are required'
});
}
const query = 'INSERT INTO users (name, email) VALUES (?, ?)';
pool.query(query, [name, email], (err, result) => {
if (err) {
// Handle duplicate email error specifically
if (err.code === 'ER_DUP_ENTRY') {
return res.status(409).json({
error: 'Duplicate email',
message: 'This email is already registered'
});
}
handleDatabaseError(err, res);
return;
}
console.log('User created successfully with ID:', result.insertId);
res.status(201).json({
id: result.insertId,
name,
email,
message: 'User created successfully'
});
});
});
// PUT update user
app.put('/api/users/:id', (req, res) => {
const { id } = req.params;
const { name, email } = req.body;
console.log(`PUT /api/users/${id} - Updating user:`, req.body);
// Input validation
if (!name || !email) {
console.log('Invalid input - Missing required fields');
return res.status(400).json({
error: 'Invalid input',
message: 'Name and email are required'
});
}
const query = 'UPDATE users SET name = ?, email = ? WHERE id = ?';
pool.query(query, [name, email, id], (err, result) => {
if (err) {
// Handle duplicate email error
if (err.code === 'ER_DUP_ENTRY') {
return res.status(409).json({
error: 'Duplicate email',
message: 'This email is already registered'
});
}
handleDatabaseError(err, res);
return;
}
if (result.affectedRows === 0) {
console.log('User not found with ID:', id);
return res.status(404).json({
error: 'Not found',
message: 'User not found'
});
}
console.log('User updated successfully:', id);
res.json({
id,
name,
email,
message: 'User updated successfully'
});
});
});
// DELETE user
app.delete('/api/users/:id', (req, res) => {
const { id } = req.params;
console.log(`DELETE /api/users/${id} - Deleting user`);
const query = 'DELETE FROM users WHERE id = ?';
pool.query(query, [id], (err, result) => {
if (err) {
handleDatabaseError(err, res);
return;
}
if (result.affectedRows === 0) {
console.log('User not found with ID:', id);
return res.status(404).json({
error: 'Not found',
message: 'User not found'
});
}
console.log('User deleted successfully:', id);
res.json({
message: 'User deleted successfully',
id: id
});
});
});
// Handle 404 errors
app.use((req, res) => {
res.status(404).json({
error: 'Not found',
message: 'The requested resource was not found'
});
});
// Handle other errors
app.use((err, req, res, next) => {
console.error('Server Error:', err);
res.status(500).json({
error: 'Server error',
message: 'An unexpected error occurred'
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
console.log(`Access the application at http://localhost:${PORT}`);
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM received. Closing HTTP server and database connection...');
pool.end((err) => {
if (err) {
console.error('Error closing database connection:', err);
process.exit(1);
}
process.exit(0);
});
});
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>User Management System</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Arial, sans-serif;
max-width: 1000px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
margin-bottom: 30px;
text-align: center;
font-size: 2em;
}
h2 {
color: #444;
margin-bottom: 20px;
font-size: 1.5em;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
color: #555;
font-weight: 500;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.form-group input:focus {
outline: none;
border-color: #4CAF50;
box-shadow: 0 0 5px rgba(76, 175, 80, 0.2);
}
button {
background-color: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #45a049;
}
button.edit-btn {
background-color: #2196F3;
}
button.edit-btn:hover {
background-color: #1976D2;
}
button.delete-btn {
background-color: #f44336;
}
button.delete-btn:hover {
background-color: #d32f2f;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
background-color: white;
}
th,
td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #f8f9fa;
font-weight: 600;
color: #333;
}
tr:hover {
background-color: #f5f5f5;
}
.error {
color: #f44336;
margin-top: 5px;
font-size: 14px;
}
.success {
color: #4CAF50;
margin-top: 5px;
font-size: 14px;
}
.action-buttons {
display: flex;
gap: 5px;
}
#notification {
position: fixed;
top: 20px;
right: 20px;
padding: 15px;
border-radius: 4px;
color: white;
display: none;
z-index: 1000;
}
.loading {
text-align: center;
padding: 20px;
display: none;
}
</style>
</head>
<body>
<div class="container">
<h1>User Management System</h1>
<div id="notification"></div>
<div id="userForm">
<h2>Add/Edit User</h2>
<form id="submitForm" onsubmit="saveUser(event)">
<input type="hidden" id="userId">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" required>
<div id="nameError" class="error"></div>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" required>
<div id="emailError" class="error"></div>
</div>
<button type="submit">Save User</button>
<button type="button" onclick="resetForm()" style="background-color: #777;">Cancel</button>
</form>
</div>
<div id="userList">
<h2>Users List</h2>
<div class="loading" id="loading">Loading users...</div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="userTableBody"></tbody>
</table>
</div>
</div>
<script>
// Base URL untuk API
const API_BASE_URL = 'http://localhost:3000/api/users';
document.addEventListener('DOMContentLoaded', loadUsers);
function showNotification(message, type) {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.style.backgroundColor = type === 'success' ? '#4CAF50' : '#f44336';
notification.style.display = 'block';
setTimeout(() => {
notification.style.display = 'none';
}, 3000);
}
function loadUsers() {
const loading = document.getElementById('loading');
loading.style.display = 'block';
fetch(API_BASE_URL)
.then(response => {
if (!response.ok) throw new Error('Failed to fetch users');
return response.json();
})
.then(users => {
const tableBody = document.getElementById('userTableBody');
tableBody.innerHTML = '';
users.forEach(user => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${escapeHtml(user.name)}</td>
<td>${escapeHtml(user.email)}</td>
<td class="action-buttons">
<button class="edit-btn" onclick="editUser(${user.id}, '${escapeHtml(user.name)}', '${escapeHtml(user.email)}')">Edit</button>
<button class="delete-btn" onclick="deleteUser(${user.id})">Delete</button>
</td>
`;
tableBody.appendChild(row);
});
})
.catch(error => {
console.error('Error loading users:', error);
showNotification('Error loading users', 'error');
})
.finally(() => {
loading.style.display = 'none';
});
}
async function saveUser(event) {
event.preventDefault();
const userId = document.getElementById('userId').value;
const name = document.getElementById('name').value.trim();
const email = document.getElementById('email').value.trim();
// Reset error messages
document.getElementById('nameError').textContent = '';
document.getElementById('emailError').textContent = '';
// Validation
if (name.length < 2) {
document.getElementById('nameError').textContent = 'Name must be at least 2 characters long';
return;
}
if (!isValidEmail(email)) {
document.getElementById('emailError').textContent = 'Please enter a valid email address';
return;
}
try {
const method = userId ? 'PUT' : 'POST';
const url = userId ? `${API_BASE_URL}/${userId}` : API_BASE_URL;
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, email })
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText);
}
const data = await response.json();
resetForm();
loadUsers();
showNotification(userId ? 'User updated successfully' : 'User added successfully', 'success');
} catch (error) {
console.error('Error saving user:', error);
showNotification(error.message, 'error');
}
}
function editUser(id, name, email) {
document.getElementById('userId').value = id;
document.getElementById('name').value = name;
document.getElementById('email').value = email;
document.getElementById('name').focus();
}
async function deleteUser(id) {
if (!confirm('Are you sure you want to delete this user?')) return;
try {
const response = await fetch(`${API_BASE_URL}/${id}`, {
method: 'DELETE'
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(errorText);
}
loadUsers();
showNotification('User deleted successfully', 'success');
} catch (error) {
console.error('Error deleting user:', error);
showNotification('Error deleting user', 'error');
}
}
function resetForm() {
document.getElementById('submitForm').reset();
document.getElementById('userId').value = '';
document.getElementById('nameError').textContent = '';
document.getElementById('emailError').textContent = '';
}
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
</script>
</body>
</html>
database.sql
CREATE DATABASE IF NOT EXISTS crud_db;
USE crud_db;
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Kita telah membuat contoh aplikasi CRUD sederhana menggunakan Node.js, MySQL, dan HTML. Berikut adalah penjelasan cara menggunakan dan mengatur aplikasinya:
Persiapan Database:
Install MySQL di komputer Anda
Buat database dan tabel menggunakan perintah SQL yang ada di bagian
database.sql
Instalasi dan Konfigurasi:
# Buat direktori baru dan masuk ke dalamnya
mkdir simple-crud-app
cd simple-crud-app
# Copy semua file dari kode di atas ke direktori yang sesuai
# Install dependencies
npm install
Konfigurasi Database:
Buka file
server.js
Sesuaikan konfigurasi MySQL dengan pengaturan Anda:
host
user
password
database
Menjalankan Aplikasi:
node server.js
Akses Aplikasi:
Buka browser dan akses
http://localhost:3000
Fitur yang tersedia dalam aplikasi ini:
Menampilkan daftar pengguna
Menambah pengguna baru
Mengubah data pengguna
Menghapus pengguna
Struktur Aplikasi:
server.js
: File utama server Node.js dengan Expresspublic/index.html
: Halaman web utama dengan HTML dan JavaScriptdatabase.sql
: Script SQL untuk membuat database dan tabel
Teknologi yang digunakan:
Backend: Node.js dengan Express
Database: MySQL
Frontend: HTML, CSS, dan JavaScript vanilla
API: RESTful API untuk operasi CRUD
Apakah Anda ingin saya menjelaskan bagian tertentu dari kode ini lebih detail?
Last updated