# 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
```

```javascript

{
  "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
```

```javascript


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
```

```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
```

```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`

2. Instalasi dan Konfigurasi:

```bash
# 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
```

3. Konfigurasi Database:

* Buka file `server.js`
* Sesuaikan konfigurasi MySQL dengan pengaturan Anda:
  * host
  * user
  * password
  * database

4. Menjalankan Aplikasi:

```bash
node server.js
```

5. 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?


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://triyono.gitbook.io/tutorial/java-script/crud-sederhana-javascript-dan-html.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
