이전 글에서 Firebase의 Firestore Database를 리용하여 간단한 게시판 기능을 구현하는 것을 소개한 바 있었다.
https://blog.naver.com/mythee1/223499829728
이렇게 만들었던 게시판 역시 글의 수가 많아지는 경우, 적절한 분량 단위로 페이지를 나눌수 있도록 Pagination을 적용하였다. 또한 보다 쉬운 구현을 위해, Firebase의 순차적인 Query로 인해 이전 데이터로 돌아가 표시하기 어려운 점을 고려해, 페이지 이동은 우선은 “다음 페이지” 이동만을 구현하기로 했다.
그 결과, 화면의 구성은 다음과 같은 형태가 되었는데,
구현하는 방법은 바로 전의 글(https://blog.naver.com/mythee1/223509401135)에서 상품 DB를 화면에 표시하면서 Pagination을 적용했던 것과 원리는 동일하다.
우선 기존에 새 글 작성용으로 만들어 두었던 버튼 앞에 “다음 페이지” 이동을 위한 버튼을 추가하고, <span> 태그와 currentPage 요소를 이용해 현재 페이지를 표시하도록 구성했다.
그리고, 전역변수의 형태로 페이지당 문서의 개수를 지정해 주고, 각 페이지의 마지막 출력을 저장하는 변수와 현재 페이지 번호를 저장하는 변수를 선언해 주었다.
그리고, 게시판의 내용을 실제로 표시하는 부분은
매 페이지마다 반복적으로 표시하는 것을 원활히 하기 위해, 함수의 형태로 바꾸어주고,
첫 실행은 다음과 같은 방식으로 해당 함수가 호출되도록 구성했다.
게시판의 내용을 실제로 표시하는 함수는 앞 부분에서 해당 페이지 출력의 마지막 레코드를 저장하는 변수 lastVisible을 이용하여 페이지 단위의 출력을 구현했다.
“다음 페이지” 버튼이 실행된 경우의 handler는 다음과 같이 구성해서 위의 함수가 다시 호출되도록 하였다.
전체 소스는 다음과 같다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>게시판</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<style>
table {
border-collapse: collapse; /* 셀 구분선을 합칩니다 */
width: 100%; /* 테이블의 너비를 화면 전체로 설정합니다 */
margin: 0 5px;
}
table, th, td {
border: 1px solid black; /* 테이블과 셀에 모두 외곽선을 추가합니다 */
}
.left-aligned-cell {
text-align: left;
}
input, textarea {
border: 1px solid black !important; /* 외곽선의 너비를 2px로 설정합니다 */
}
</style>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.6.5/firebase-storage.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script src="/firebaseConfig.js"></script>
</head>
<body>
<div class="container mt-5 mb-3">
<h4> 게시판 ...</h4>
<table id="posts" style="text-align: center; border: 2px solid black;">
<tr>
<th style="font-weight: bold; width: 100px;">No.</th>
<th style="font-weight: bold; width: 400px;">제목</th>
<th style="font-weight: bold; width: 1500px;">내용</th>
<th style="font-weight: bold; width: 100px;">작성자</th>
<th style="font-weight: bold; width: 150px;">Date</th>
</tr>
<!-- 이곳에 게시물이 동적으로 추가됩니다 -->
</table>
</div>
<div class="container">
<div id="productList" class="m-3"></div>
<div class="m-3">
<span id="currentPage" style="margin: 10px 10px;"></span>
<button id="nextPage" class="btn btn-sm btn-outline-danger">다음 페이지</button>
<span id="space" style="margin: 10px 10px;"></span>
<button id="writeNew" class="btn btn-sm btn-primary" >새글 쓰기</button>
</div>
</div>
<script>
var db = firebase.firestore();
var pageSize = 6
; // 한 페이지에 표시할 항목 수
var firstVisible; // 첫 표시된 항목
var lastVisible; // 마지막 표시된 항목
var currentPage = 1; // 현재 페이지 번호
function readPosts() {
var query = db.collection("posts").orderBy("postNumber", "desc").limit(pageSize);
if (lastVisible) {
query = query.startAfter(lastVisible);
} else if (firstVisible && currentPage < 1) {
query = query.endBefore(firstVisible);
}
query.get().then((querySnapshot) => {
if (!querySnapshot.empty) {
firstVisible = querySnapshot.docs[0];
lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
}
var postsTable = document.getElementById('posts');
while (postsTable.rows.length > 1) { // 기존에 추가된 게시물을 제거합니다
postsTable.deleteRow(postsTable.rows.length - 1);
}
querySnapshot.forEach((doc) => {
var row = postsTable.insertRow();
var postNumberCell = row.insertCell();
var titleCell = row.insertCell();
var contentCell = row.insertCell();
contentCell.className = 'left-aligned-cell'; // CSS 클래스 추가
contentCell.textContent = doc.data().content;
var authorCell = row.insertCell();
var createdAtCell = row.insertCell();
postNumberCell.textContent = doc.data().postNumber;
titleCell.textContent = doc.data().title;
contentCell.textContent = doc.data().content;
authorCell.textContent = doc.data().author;
createdAtCell.textContent = doc.data().createdAt.toDate().toLocaleString();
});
}).catch((error) => {
console.error("Error reading posts: ", error);
});
}
function updatePageNumber() {
document.getElementById('currentPage').textContent = "현재 페이지: " + currentPage;
}
window.onload = function() {
readPosts();
updatePageNumber();
}
$('#nextPage').click(function() {
currentPage++;
readPosts( );
updatePageNumber();
});
$('#writeNew').click(function () {
setTimeout(() => window.location.href = "/boardwrite.html", 100)
});
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>

