반응형
목차
ajax로 페이징을 구현 했는데 페이지 이동이 되었다가 다시 같은 페이지가 호출이 되었다.
콘솔 보면 2페이지 데이터를 정상적으로 가져왔다가 다시 1페이지가 호출이 되고 있다.
간단한 원인 이었는데 꽤 많은 시간 삽질 끝에 나중에 다시 봐야지 하고 넘어 갔었다가 다시 봐서 해결 했다.
before source 🙂
/**
* 페이지네이션을 그린다.
* @param paging
*/
function drawPagination(paging) {
let pageHtml = "";
pageHtml += "<ul class='pagination'>";
//first
const first = parseInt(paging.firstPage);
pageHtml += "<li class='paginate_button page-item first'>";
if (paging.currentPage === paging.firstPage) {
pageHtml += "<button class='page-link' disabled>";
} else {
pageHtml += "<button class='page-link' style='cursor: pointer;' onclick='movePage("+ first +")'>";
}
pageHtml += "<span class='hidden'>first page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
//prev
const prev = parseInt(paging.currentPage) -1;
pageHtml += "<li class='paginate_button page-item prev'>";
if (paging.firstPage === paging.currentPage) {
pageHtml += "<button class='page-link' disabled>";
} else {
pageHtml += "<button class='page-link' style='cursor: pointer;' onclick='movePage("+ prev +")'>";
}
pageHtml += "<span class='hidden'>prev page</span>";
pageHtml += "</button>";
pageHtml += "</li>";
//① ~ ⑩
for (let i = paging.firstPageNo; i <= paging.lastPageNo; i++) {
pageHtml += "<li class='paginate_button page-item";
//현재 페이지가 인덱스와 같으면 active class 추가
if (paging.currentPage === i) {
pageHtml += " active'>";
pageHtml += "<button class='page-link' style='cursor: pointer;' onclick='movePage("+ i +")'>";
pageHtml += i;
pageHtml += "</button>";
pageHtml += "</li>"
} else {
pageHtml += "'>";
pageHtml += "<button class='page-link' style='cursor: pointer;' onclick='movePage("+ i +")'>";
pageHtml += i;
pageHtml += "</button>";
pageHtml += "</li>"
}
}
//next
const next = parseInt(paging.currentPage) + 1;
pageHtml += "<li class='paginate_button page-item next'>";
if (paging.currentPage === paging.lastPage) {
pageHtml += "<button class='page-link' disabled>";
} else {
pageHtml += "<button class='page-link' style='cursor: pointer;' onclick='movePage("+ next +")'>";
}
pageHtml += "<span class='hidden'>next page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
//last
const last = parseInt(paging.lastPage);
pageHtml += "<li class='paginate_button page-item last'>";
if (paging.currentPage === paging.lastPage) {
pageHtml += "<button class='page-link' disabled>";
} else {
pageHtml += "<button class='page-link' style='cursor: pointer;' onclick='movePage("+ last +")'>";
}
pageHtml += "<span class='hidden'>last page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
pageHtml += "</ul>";
//페이지네이션 영역에 반영
$(".tbl-paging").html(pageHtml);
}
after source 😎
/**
* 페이지네이션을 그린다.
* @param paging
*/
function drawPagination(paging) {
let pageHtml = "";
pageHtml += "<ul class='pagination'>";
//first
const first = parseInt(paging.firstPage);
pageHtml += "<li class='paginate_button page-item first'>";
if (paging.currentPage === paging.firstPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ first +")'>";
}
pageHtml += "<span class='hidden'>first page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
//prev
const prev = parseInt(paging.currentPage) -1;
pageHtml += "<li class='paginate_button page-item prev'>";
if (paging.firstPage === paging.currentPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ prev +")'>";
}
pageHtml += "<span class='hidden'>prev page</span>";
pageHtml += "</button>";
pageHtml += "</li>";
//① ~ ⑩
for (let i = paging.firstPageNo; i <= paging.lastPageNo; i++) {
pageHtml += "<li class='paginate_button page-item";
//현재 페이지가 인덱스와 같으면 active class 추가
if (paging.currentPage === i) {
pageHtml += " active'>";
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ i +")'>";
pageHtml += i;
pageHtml += "</button>";
pageHtml += "</li>"
} else {
pageHtml += "'>";
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ i +")'>";
pageHtml += i;
pageHtml += "</button>";
pageHtml += "</li>"
}
}
//next
const next = parseInt(paging.currentPage) + 1;
pageHtml += "<li class='paginate_button page-item next'>";
if (paging.currentPage === paging.lastPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ next +")'>";
}
pageHtml += "<span class='hidden'>next page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
//last
const last = parseInt(paging.lastPage);
pageHtml += "<li class='paginate_button page-item last'>";
if (paging.currentPage === paging.lastPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ last +")'>";
}
pageHtml += "<span class='hidden'>last page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
pageHtml += "</ul>";
//페이지네이션 영역에 반영
$(".tbl-paging").html(pageHtml);
}
달라진 부분은 동적으로 만든 button에 type을 button으로 설정했다.
이번에 알게된 사실인데 button에 type을 명시하지 않을 경우 default값은 submit이라고 한다.
그러니 버튼을 누를 때마다 ajax로 2페이지를 가져온 다음 form submit을 한번 더 하게 된거다.
form action에 아무값도 주지 않았기에 현재 페이지로 submit을 태워서 계속 같은 페이지가 로드 된 거다.
사실을 알게 된 후 form action에 존재하지 않는 주소를 줬더니 예상대로 404 에러가 발생했다.
이 삽질을 통해 느낀 교훈: button을 만들 때 명시적으로 항상 type을 선언하도록 하자.
전체 소스(샘플용)
리팩토링 X
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<style>
li {
list-style: none;
float: left;
}
</style>
</head>
<body>
<form id="searchForm">
<select name="type" id="type">
<option value="">전체</option>
<option value="T">제목</option>
<option value="C">내용</option>
<option value="W">작성자</option>
</select>
<input type="text" name="keyword" id="keyword">
<button id="searchBtn">검색</button>
<a th:href="@{/board/reg}">글쓰기</a>
<div id="count"></div>
<table>
<thead>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
<th>등록일</th>
</thead>
<tbody id="boardBody"></tbody>
</table>
<div class="tbl-paging"></div>
</form>
<script th:inline="javascript" type="text/javascript">
//구분
const menu = "board";
//검색조건
let searchData = "";
$(function () {
getList("", 1, menu);
});
//검색
$("#searchBtn").on("click", function () {
searchData = $('#searchForm').serialize();
getList(searchData, 1, menu);
});
/**
* 페이지 이동
* @param currentPage
*/
function movePage(currentPage){
//검색조건이 있을 경우에만 검색조건 추가(검색조건 유지한 채 페이지 이동)
(searchData != null) ? getList(searchData, currentPage, menu) : getList("", currentPage, menu);
}
/**
* ajax 통신으로 리스트를 조회한다.
* @param searchParam 검색조건
* @param currentPage 현재 페이지
* @param type 메뉴타입
*/
function getList(searchParam, currentPage, type){
console.log("getList!!!!");
$.ajax({
url: "/api/" + type +"?currentPage=" + currentPage,
type:"get",
//IE 브라우저 사용 안한다는 가정하에 주석처리
// cache: false,
data: searchParam,
success: function (data){
//draw tbody
drawTbody(data, type);
//draw pagination
drawPagination(data.paging);
},
error:function(e){
}
});
}
/**
* tbody에 html을 덮어쓴다.
* @param data
* @param gubun
*/
function drawTbody(data, gubun) {
//drawHtml, draw 대상 tbody
let htmlData, targetTbody = "";
targetTbody = "boardBody";
// foreach start
for (let i = 0; i < data.list.length; i++) {
htmlData += "<tr ";
htmlData += "data-sno=" + data.list[i].boardSno + ">";
htmlData += "<td>";
htmlData += data.list[i].no;
htmlData += "</td>";
htmlData += "<td>";
htmlData += "<a href='#' onclick='detail(\"" + data.list[i].boardSno + "\")'>";
htmlData += data.list[i].title;
htmlData += "</a>";
htmlData += "</td>";
htmlData += "<td>";
htmlData += data.list[i].content;
htmlData += "</td>";
htmlData += "<td>";
htmlData += data.list[i].userId;
htmlData += "</td>";
htmlData += "<td>";
htmlData += data.list[i].regDate;
htmlData += "</td>";
htmlData += "<td>";
htmlData += "<a href='#' onclick='delBoard(\"" + data.list[i].boardSno + "\")'>삭제</a>";
htmlData += "</td>";
htmlData += "</tr>";
}
// foreach end
//tbody에 반영
$("#" + targetTbody + "").html(htmlData);
countHtml = "";
countHtml += data.count + "건";
$("#count").text(countHtml);
}
// end function getList()
//상세보기
function detail(sno) {
location.href = "/board/mod/" + sno;
}
function delBoard(sno) {
$.ajax({
url: "/api/board/" + sno,
type:"delete",
//IE 브라우저 사용 안한다는 가정하에 주석처리
// cache: false,
success: function (data) {
if(data.code === "1") alert("삭제 되었습니다.");
location.href = "/board"
},
error:function(e){
console.log(e);
}
});
}
/**
* 페이지네이션을 그린다.
* @param paging
*/
function drawPagination(paging) {
let pageHtml = "";
pageHtml += "<ul class='pagination'>";
//first
const first = parseInt(paging.firstPage);
pageHtml += "<li class='paginate_button page-item first'>";
if (paging.currentPage === paging.firstPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ first +")'>";
}
pageHtml += "<span class='hidden'>first page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
//prev
const prev = parseInt(paging.currentPage) -1;
pageHtml += "<li class='paginate_button page-item prev'>";
if (paging.firstPage === paging.currentPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ prev +")'>";
}
pageHtml += "<span class='hidden'>prev page</span>";
pageHtml += "</button>";
pageHtml += "</li>";
//① ~ ⑩
for (let i = paging.firstPageNo; i <= paging.lastPageNo; i++) {
pageHtml += "<li class='paginate_button page-item";
//현재 페이지가 인덱스와 같으면 active class 추가
if (paging.currentPage === i) {
pageHtml += " active'>";
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ i +")'>";
pageHtml += i;
pageHtml += "</button>";
pageHtml += "</li>"
} else {
pageHtml += "'>";
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ i +")'>";
pageHtml += i;
pageHtml += "</button>";
pageHtml += "</li>"
}
}
//next
const next = parseInt(paging.currentPage) + 1;
pageHtml += "<li class='paginate_button page-item next'>";
if (paging.currentPage === paging.lastPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ next +")'>";
}
pageHtml += "<span class='hidden'>next page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
//last
const last = parseInt(paging.lastPage);
pageHtml += "<li class='paginate_button page-item last'>";
if (paging.currentPage === paging.lastPage) {
pageHtml += "<button type='button' class='page-link' disabled>";
} else {
pageHtml += "<button type='button' class='page-link' style='cursor: pointer;' onclick='movePage("+ last +")'>";
}
pageHtml += "<span class='hidden'>last page</span>";
pageHtml += "</button>";
pageHtml += "</li>"
pageHtml += "</ul>";
//페이지네이션 영역에 반영
$(".tbl-paging").html(pageHtml);
}
</script>
</body>
</html>
개인 스터디 기록을 메모하는 공간이라 틀린점이 있을 수 있습니다.
틀린 점 있을 경우 댓글 부탁드립니다.
반응형
'IT > development' 카테고리의 다른 글
[ChatGPT] ChatGPT 고맙다. (0) | 2023.07.22 |
---|---|
[React.js] state 사용법 (0) | 2023.07.13 |
[dbeaver] dbeaver DDL, DML 생성 (0) | 2023.07.08 |
[JavaScript] 동적 엘리먼트 onclick 문자열 (0) | 2023.07.05 |
[JavaScript] validation (0) | 2023.06.25 |