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, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;")
                .replace(/"/g, "&quot;")
                .replace(/'/g, "&#039;");
        }
    </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:

  1. Persiapan Database:

  • Install MySQL di komputer Anda

  • Buat database dan tabel menggunakan perintah SQL yang ada di bagian database.sql

  1. 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
  1. Konfigurasi Database:

  • Buka file server.js

  • Sesuaikan konfigurasi MySQL dengan pengaturan Anda:

    • host

    • user

    • password

    • database

  1. Menjalankan Aplikasi:

node server.js
  1. Akses Aplikasi:

  • Buka browser dan akses http://localhost:3000

Fitur yang tersedia dalam aplikasi ini:

  1. Menampilkan daftar pengguna

  2. Menambah pengguna baru

  3. Mengubah data pengguna

  4. Menghapus pengguna

Struktur Aplikasi:

  • server.js: File utama server Node.js dengan Express

  • public/index.html: Halaman web utama dengan HTML dan JavaScript

  • database.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