웹페이지 만들기 방명록

148june 2025. 2. 18. 09:34
            cursorRequest.onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    const listItem = document.createElement('li');
                    listItem.setAttribute('data-id', cursor.value.id);
                    listItem.textContent = `${cursor.value.name}: ${cursor.value.message}`;

                    // 수정 버튼
                    const editButton = document.createElement('button');
                    editButton.className = 'edit-btn';
                    editButton.textContent = '수정';
                    editButton.onclick = () => editMessage(cursor.value.id, cursor.value.name, cursor.value.message);
                    listItem.appendChild(editButton);

                    // 삭제 버튼
                    const deleteButton = document.createElement('button');
                    deleteButton.className = 'delete-btn';
                    deleteButton.textContent = '삭제';
                    deleteButton.onclick = () => deleteMessage(cursor.value.id);
                    listItem.appendChild(deleteButton);

                    messagesList.appendChild(listItem);
                    cursor.continue();
                }
            };
        };

이부분의 문제 점은 

값 캡처 문제(잠재적 문제):
원래 각 버튼의 이벤트 핸들러에서 cursor.value를 직접 참조했기 때문에, 클로저 문제로 인해 의도한 값이 아닌 최신 값만 사용될 가능성이 있었습니다.

즉 

ㅁㅁ : ㅁㅁㅁ 수정 삭제

ㅇㅇ: ㅇㅇㅇ 수정 삭제 

이렇게 있을시 ㅁㅁ을 수정하고 싶어 ㅁㅁㅁ 옆 수정을 눌렀을시 ㅇㅇ 이 최신 글 일 경우 ㅇㅇ: ㅇㅇㅇ을 수정하는 문제 점이 있었다. 이문제를 해결하기 위해

// 방명록 메시지 수정 (id 유지하면서 내용만 수정)
const editMessage = (id, currentName, currentMessage) => {
    const newName = prompt("이름을 수정하세요", currentName);
    const newMessage = prompt("내용을 수정하세요", currentMessage);

    if (newName && newMessage) {
        const transaction = db.transaction('messages', 'readwrite');
        const store = transaction.objectStore('messages');

        store.get(id).onsuccess = (event) => {
            const existingMessage = event.target.result;
            if (existingMessage) {
                existingMessage.name = newName;
                existingMessage.message = newMessage;

                store.put(existingMessage); // 기존 ID 유지한 채로 수정
                transaction.oncomplete = () => {
                    loadMessages();
                };
            }
        };
    }
};

 

 

방명록 기존값을 유지하기위해  고안햇었다.

add 문제인가 싶어 put 으로 변경하기도 하였다.

 

하지만 진짜 문제는 값을 가져오는 문제에 있었던거였고

기존값

            cursorRequest.onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    const listItem = document.createElement('li');
                    listItem.setAttribute('data-id', cursor.value.id);
                    listItem.textContent = `${cursor.value.name}: ${cursor.value.message}`;

                    // 수정 버튼
                    const editButton = document.createElement('button');
                    editButton.className = 'edit-btn';
                    editButton.textContent = '수정';
                    editButton.onclick = () => editMessage(cursor.value.id, cursor.value.name, cursor.value.message);
                    listItem.appendChild(editButton);

                    // 삭제 버튼
                    const deleteButton = document.createElement('button');
                    deleteButton.className = 'delete-btn';
                    deleteButton.textContent = '삭제';
                    deleteButton.onclick = () => deleteMessage(cursor.value.id);
                    listItem.appendChild(deleteButton);

                    messagesList.appendChild(listItem);
                    cursor.continue();
                }
            };
        };

변경후

cursorRequest.onsuccess = (event) => {
    const cursor = event.target.result;
    if (cursor) {
        // 커서의 값을 별도의 변수에 저장
        const { id, name, message } = cursor.value;

        const listItem = document.createElement('li');
        listItem.setAttribute('data-id', id);
        
        // 별도의 요소(예: span)를 사용하면 텍스트와 버튼을 구분하기 쉽습니다.
        const textSpan = document.createElement('span');
        textSpan.textContent = `${name}: ${message}`;
        listItem.appendChild(textSpan);

        // 수정 버튼 생성
        const editButton = document.createElement('button');
        editButton.className = 'edit-btn';
        editButton.textContent = '수정';
        // 이벤트 핸들러에서 별도의 변수 사용
        editButton.onclick = () => editMessage(id, name, message);
        listItem.appendChild(editButton);

        // 삭제 버튼 생성
        const deleteButton = document.createElement('button');
        deleteButton.className = 'delete-btn';
        deleteButton.textContent = '삭제';
        deleteButton.onclick = () => deleteMessage(id);
        listItem.appendChild(deleteButton);

        messagesList.appendChild(listItem);
        cursor.continue();
    }
};

전체코드는 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>방명록</title>
    <style>
        .section {
            margin: 20px 0;
            padding: 10px;
        }

        .guest-book ul {
            list-style-type: none;
        }

        .guest-book li {
            margin-bottom: 10px;
        }

        textarea, input[type="text"] {
            width: 100%;
            padding: 8px;
            font-size: 16px;
            margin-bottom: 10px;
            box-sizing: border-box;
        }

        button {
            margin-top: 10px;
            padding: 10px 20px;
            background-color: #000000;
            color: white;
            border: none;
            cursor: pointer;
        }

        button:hover {
            background-color: #333;
        }

        .edit-btn {
            background-color: #0067A3;
            margin-left: 10px;
        }

        .delete-btn {
            background-color: #e74c3c;
            margin-left: 10px;
        }
    </style>
</head>
<body>
    <div class="guest-book">
        <h3>방명록</h3>
        <form id="guestBookForm">
            <label for="name">이름:</label>
            <input type="text" id="name" name="name" required placeholder="이름을 입력하세요">
            <label for="message">내용:</label>
            <textarea id="message" name="message" required placeholder="방명록 내용을 입력하세요"></textarea>
            <button type="submit">저장</button>
        </form>

        <h4>방명록 내용</h4>
        <ul id="guestMessages"></ul>
    </div>

    <script>
        let db;

        // IndexedDB 연결 함수
        const openDb = () => {
            const request = indexedDB.open('GuestBookDB', 1);

            request.onupgradeneeded = (event) => {
                db = event.target.result;
                if (!db.objectStoreNames.contains('messages')) {
                    db.createObjectStore('messages', { keyPath: 'id' });
                }
            };

            request.onsuccess = (event) => {
                db = event.target.result;
                console.log("Database opened successfully.");
                loadMessages(); // DB가 완전히 열린 후에 실행
            };

            request.onerror = (event) => {
                console.error("Database error:", event.target.errorCode);
            };
        };

        const loadMessages = () => {
            if (!db) {
                console.error("Database is not initialized yet.");
                return;
            }

            const transaction = db.transaction('messages', 'readonly');
            const store = transaction.objectStore('messages');
            const cursorRequest = store.openCursor();

            const messagesList = document.getElementById('guestMessages');
            messagesList.innerHTML = "";  
            /*
            cursorRequest.onsuccess = (event) => {
                const cursor = event.target.result;
                if (cursor) {
                    const listItem = document.createElement('li');
                    listItem.setAttribute('data-id', cursor.value.id);
                    listItem.textContent = `${cursor.value.name}: ${cursor.value.message}`;

                    // 수정 버튼
                    const editButton = document.createElement('button');
                    editButton.className = 'edit-btn';
                    editButton.textContent = '수정';
                    editButton.onclick = () => editMessage(cursor.value.id, cursor.value.name, cursor.value.message);
                    listItem.appendChild(editButton);

                    // 삭제 버튼
                    const deleteButton = document.createElement('button');
                    deleteButton.className = 'delete-btn';
                    deleteButton.textContent = '삭제';
                    deleteButton.onclick = () => deleteMessage(cursor.value.id);
                    listItem.appendChild(deleteButton);

                    messagesList.appendChild(listItem);
                    cursor.continue();
                }
            };
        };
            */
            cursorRequest.onsuccess = (event) => {
    const cursor = event.target.result;
    if (cursor) {
        // 커서의 값을 별도의 변수에 저장
        const { id, name, message } = cursor.value;

        const listItem = document.createElement('li');
        listItem.setAttribute('data-id', id);
        
        // 별도의 요소(예: span)를 사용하면 텍스트와 버튼을 구분하기 쉽습니다.
        const textSpan = document.createElement('span');
        textSpan.textContent = `${name}: ${message}`;
        listItem.appendChild(textSpan);

        // 수정 버튼 생성
        const editButton = document.createElement('button');
        editButton.className = 'edit-btn';
        editButton.textContent = '수정';
        // 이벤트 핸들러에서 별도의 변수 사용
        editButton.onclick = () => editMessage(id, name, message);
        listItem.appendChild(editButton);

        // 삭제 버튼 생성
        const deleteButton = document.createElement('button');
        deleteButton.className = 'delete-btn';
        deleteButton.textContent = '삭제';
        deleteButton.onclick = () => deleteMessage(id);
        listItem.appendChild(deleteButton);

        messagesList.appendChild(listItem);
        cursor.continue();
    }
};

// 방명록 메시지 추가 (기존 데이터 덮어쓰지 않도록 add 사용)
const addMessage = (name, message) => {
    if (!db) {
        console.error("Database not initialized.");
        return;
    }

    const transaction = db.transaction('messages', 'readwrite');
    const store = transaction.objectStore('messages');

    const newEntry = { id: Date.now(), name, message };

    const request = store.add(newEntry);

    request.onsuccess = () => {
        loadMessages();
    };

    request.onerror = (event) => {
        console.error("Error adding message:", event.target.error);
    };
};

// 방명록 메시지 수정 (id 유지하면서 내용만 수정)
const editMessage = (id, currentName, currentMessage) => {
    const newName = prompt("이름을 수정하세요", currentName);
    const newMessage = prompt("내용을 수정하세요", currentMessage);

    if (newName && newMessage) {
        const transaction = db.transaction('messages', 'readwrite');
        const store = transaction.objectStore('messages');

        store.get(id).onsuccess = (event) => {
            const existingMessage = event.target.result;
            if (existingMessage) {
                existingMessage.name = newName;
                existingMessage.message = newMessage;

                store.put(existingMessage); // 기존 ID 유지한 채로 수정
                transaction.oncomplete = () => {
                    loadMessages();
                };
            }
        };
    }
};

// 방명록 메시지 삭제 (id 기준으로 정확한 데이터 삭제)
const deleteMessage = (id) => {
    const transaction = db.transaction('messages', 'readwrite');
    const store = transaction.objectStore('messages');
    store.delete(id);

    transaction.oncomplete = () => {
        loadMessages();
    };
};

        // 폼 제출 처리
        document.getElementById('guestBookForm').addEventListener('submit', (event) => {
            event.preventDefault();

            const name = document.getElementById('name').value;
            const message = document.getElementById('message').value;

            addMessage(name, message);

            document.getElementById('name').value = '';
            document.getElementById('message').value = '';
        });
    }
        // DB 열기
        openDb();
    </script>
</body>
</html>

html블럭으로 가동한다면

방명록

방명록 내용

     

    방명록 웹페이지를 만들면  indexedb를 알게되었고 

    커서값을 직접 가져오는 식으로 하려 햇으나 문제점에 도달하게되었고

    대신 값을 저장한것을 가져오는 식으로 변경하여 문제을 해결 할수 있게 되었다.