const productListUrl = `${URI}/api/product/list?category=MUG`;
async function fetchData() {
try {
const response = await fetch(productListUrl);
const jsonData = await response.json();
if (Array.isArray(jsonData.data)) {
const links = jsonData.data.map(data => `
<a href="../list-detail/list-detail.html?id=${data._id}" class="item-box">
<img src="${data.imgSrc}" alt="${data.name}" class="item-image">
<h5 class="item-name">${data.name}</h5>
<p class="item-price">${data.price}원 (부가세포함)</p>
</a>
`);
itemArea.innerHTML = links.join('');
mainTitle.innerHTML = jsonData.data[0].category;
itemCount.innerHTML = `${jsonData.data.length}`;
const rowsPerPage = 15;
const rows = jsonData.data;
const rowsCount = jsonData.data.length;
const pageCount = Math.ceil(rowsCount / rowsPerPage);
// 페이지 버튼들을 담을 컨테이너
const pagenationNumbers = document.querySelector('.pagenation-numbers');
//페이지네이션 생성
for (let i = 1; i <= pageCount; i++) {
pagenationNumbers.innerHTML += `<li><a href="">${i}</a></li>`;
}
const numberBtn = pagenationNumbers.querySelectorAll('a');
console.log(numberBtn);
numberBtn.forEach((item, index) => {
item.addEventListener('click', (e) => {
e.preventDefault();
// console.log(index);
// 테이블 출력 함수
displayRaw(index);
});
});
function displayRaw(index) {
let start = index * rowsPerPage;
let end = start + rowsPerPage;
let rowArray = rows.slice(0, 15);
for (let ra of rowArray) {
ra.style.display = "none";
}
let newRows = rowArray.slice(start, end);
for (let nr of newRows) {
nr.style.display = 'block';
}
for (let nb of numberBtn) {
nb.classList.remove('active');
}
numberBtn[index].target.classList.add('active');
}
displayRaw(0);
}
} catch (error) {
console.log(error);
}
}
서버에서 json데이터를 받아와 15개씩 나눠 페이지를 구성해주는 페이지네이션을 만들었다.
그런데 위 방식대로 하면 display-none 속성을 적용할 수 없다는 에러가 출력이 된다.
json 데이터는 DOM 엘리먼트가 아니기 때문에 위 속성을 적용할 수 없었다.
대신 displayRaw 함수에서는 itemArea 엘리먼트 내부의 a 태그 엘리먼트를 가져와서 처리해주면 된다.
아래는 수정된 코드다.
const productListUrl = `${URI}/api/product/list?category=MUG`;
async function fetchData() {
try {
const response = await fetch(productListUrl);
const jsonData = await response.json();
if (Array.isArray(jsonData.data)) {
const links = jsonData.data.map(data => `
<a href="../list-detail/list-detail.html?id=${data._id}" class="item-box">
<img src="${data.imgSrc}" alt="${data.name}" class="item-image">
<h5 class="item-name">${data.name}</h5>
<p class="item-price">${data.price}원 (부가세포함)</p>
</a>
`);
itemArea.innerHTML = links.join('');
mainTitle.innerHTML = jsonData.data[0].category;
itemCount.innerHTML = `${jsonData.data.length}`;
const rowsPerPage = 15;
const rows = itemArea.querySelectorAll('.item-box');
const rowsCount = rows.length;
const pageCount = Math.ceil(rowsCount / rowsPerPage);
// 페이지 버튼들을 담을 컨테이너
const pagenationNumbers = document.querySelector('.pagenation-numbers');
//페이지네이션 생성
for (let i = 1; i <= pageCount; i++) {
pagenationNumbers.innerHTML += `<li><a href="">${i}</a></li>`;
}
const numberBtn = pagenationNumbers.querySelectorAll('a');
console.log(numberBtn);
numberBtn.forEach((item, index) => {
item.addEventListener('click', (e) => {
e.preventDefault();
// console.log(index);
// 테이블 출력 함수
displayRaw(index);
});
});
function displayRaw(index) {
let start = index * rowsPerPage;
let end = start + rowsPerPage;
for (let i = 0; i < rowsCount; i++) {
if (i >= start && i < end) {
rows[i].style.display = 'block';
} else {
rows[i].style.display = 'none';
}
}
for (let nb of numberBtn) {
nb.classList.remove('active');
}
numberBtn[index].classList.add('active');
}
displayRaw(0);
}
} catch (error) {
console.log(error);
}
}
페이지네이션 기능을 구현하고 나서 가격 높은 순, 낮은 순 각각 버튼을 만들고 sort 메서드를 사용해 구현했다.
버튼을 눌렀을 때 정렬 기능은 정상적으로 동작했지만 한 페이지에 15개씩 끊어서 표시해주는 기능이 동작하지 않아 모든 제품들이 한번에 표시되었다.아래는 문제의 코드다.
//상품 목록 불러오는 fetchData함수 선언
async function fetchData() {
try {
// fetch 함수를 사용해 상품 목록 데이터를 서버에서 가져옴
const response = await fetch(productListUrl);
const jsonData = await response.json();
let jsonDataData = jsonData.data;
document.querySelector('.sorting-low-price-button').addEventListener('click', function () {
// 가격이 낮은 순서대로 정렬
jsonDataData = jsonData.data.sort((a, b) => a.price - b.price);
if (Array.isArray(jsonDataData)) {
const links = jsonDataData.map(data => `
<a href="../list-detail/list-detail.html?id=${data._id}" class="item-box">
<img src="../../assets/product-imgs/${data._id}.jpeg" alt="${data.name}" class="item-image">
<h5 class="item-name">${data.name}</h5>
<p class="item-price">${data.price}원<br>(부가세포함)</p>
</a>
`);
//상품 목록 UI 브라우저에 출력
itemArea.innerHTML = links.join('');
mainTitle.innerHTML = jsonData.data[0].category;
itemCount.innerHTML = `${jsonData.data.length}`;
}
});
document.querySelector('.sorting-high-price-button').addEventListener('click', function () {
// 가격이 높은 순서대로 정렬
jsonDataData = jsonData.data.sort((a, b) => b.price - a.price);
if (Array.isArray(jsonDataData)) {
const links = jsonDataData.map(data => `
<a href="../list-detail/list-detail.html?id=${data._id}" class="item-box">
<img src="../../assets/product-imgs/${data._id}.jpeg" alt="${data.name}" class="item-image">
<h5 class="item-name">${data.name}</h5>
<p class="item-price">${data.price}원<br>(부가세포함)</p>
</a>
`);
//상품 목록 UI 브라우저에 출력
itemArea.innerHTML = links.join('');
mainTitle.innerHTML = jsonData.data[0].category;
itemCount.innerHTML = `${jsonData.data.length}`;
}
});
//상품 목록 데이터가 배열일 경우, 상품 목록 UI 생성
if (Array.isArray(jsonDataData)) {
const links = jsonDataData.map(data => `
<a href="../list-detail/list-detail.html?id=${data._id}" class="item-box">
<img src="../../assets/product-imgs/${data._id}.jpeg" alt="${data.name}" class="item-image">
<h5 class="item-name">${data.name}</h5>
<p class="item-price">${data.price}원<br>(부가세포함)</p>
</a>
`);
//상품 목록 UI 브라우저에 출력
itemArea.innerHTML = links.join('');
mainTitle.innerHTML = jsonData.data[0].category;
itemCount.innerHTML = `${jsonData.data.length}`;
//페이지네이션 구현
const rowsPerPage = 18;
const rows = itemArea.querySelectorAll('.item-box');
const rowsCount = rows.length;
const pageCount = Math.ceil(rowsCount / rowsPerPage);
// 페이지 버튼들을 담을 컨테이너
const pagenationNumbers = document.querySelector('.pagenation-numbers');
//페이지네이션 버튼 생성
for (let i = 1; i <= pageCount; i++) {
pagenationNumbers.innerHTML += `<li><a href="">${i}</a></li>`;
}
//페이지 버튼 선택
const numberBtn = pagenationNumbers.querySelectorAll('a');
//각 페이지 버튼을 클릭했을 때 발생하는 이벤트 등록
numberBtn.forEach((item, index) => {
item.addEventListener('click', (e) => {
e.preventDefault();
//페이지 번호를 인자로 받아, 해당 페이지에 해당하는 상품 목록 출력
displayRaw(index);
});
});
//각 페이지에 해당하는 상품 목록 출력하는 함수
function displayRaw(index) {
let start = index * rowsPerPage;
let end = start + rowsPerPage;
//for문으로 rows 배열 내의 상품 목록중 해당 페이지에 해당하는 상품 목록 출력
for (let i = 0; i < rowsCount; i++) {
if (i >= start && i < end) {
rows[i].style.display = 'block';
} else {
rows[i].style.display = 'none';
}
}
//페이지 버튼 활성화 표시를 위해 active 클래스 적용하고 이전 페이지 버튼의 활성화 클래스 제거
for (let nb of numberBtn) {
nb.classList.remove('active');
}
numberBtn[index].classList.add('active');
}
displayRaw(0);
return
}
} catch (error) {
console.log(error);
}
}
fetchData();
아직까지 기능구현에만 중점을 둔 나머지, 중복되는 코드들도 많고, 때문에 가독성이 너무 떨어진다.
여튼 현재 문제는 그것보다 기능이 정상동작이 안되는 거니, 일단 문제를 살펴보자,,, 정말 간단한 문제인데 한참동안 고민했던 것 같다.
정렬 버튼 또한 페이지네이션 코드를 넣어줬어야 했는데, 기본 출력 값에만 페이지네이션 코드를 넣어주었다. 이것가지고 몇시간 동안 끙끙대면서 고민한 나 제법 바보일지도,,,,?😇
여튼 해당 코드를 이벤트마다 다 붙여넣어줬더니 정상동작했다. 다만, 위에서 얘기한 것 처럼 중복되는 코드들이 많았는데, 페이지네이션 코드를 두번이나 더 넣어줬더니 정말 더러운 코드가 완성되어버렸다.... 누덕쓰~
보기 너무 싫어 중복되는 코드는 함수로 묶어 호다닥 빼버렸다. 아래는 오류도 고치고 나름 깔끔해진 코드.
//상품 목록 불러오는 fetchData함수 선언
async function fetchData() {
try {
// fetch 함수를 사용해 상품 목록 데이터를 서버에서 가져옴
const response = await fetch(productListUrl);
const jsonData = await response.json();
let jsonDataData = jsonData.data;
function innerData() {
const links = jsonDataData.map(data => `
<a href="../list-detail/list-detail.html?id=${data._id}" class="item-box">
<img src="../../assets/product-imgs/${data._id}.jpeg" alt="${data.name}" class="item-image">
<h5 class="item-name">${data.name}</h5>
<p class="item-price">${data.price}원<br>(부가세포함)</p>
</a>
`);
//상품 목록 UI 브라우저에 출력
itemArea.innerHTML = links.join('');
mainTitle.innerHTML = jsonData.data[0].category;
itemCount.innerHTML = `${jsonData.data.length}`;
// 페이지네이션 구현
const rowsPerPage = 15; // 한 페이지에 보여줄 상품 개수
const rows = itemArea.querySelectorAll('.item-box'); // 상품 목록 영역에서 'item-box' 클래스를 가진 요소들을 모두 가져와서 배열로 저장
const rowsCount = rows.length; // 상품 목록의 총 개수
const pageCount = Math.ceil(rowsCount / rowsPerPage); // 총 페이지 수 계산
// 페이지 버튼들을 담을 컨테이너
const pagenationNumbers = document.querySelector('.pagenation-numbers');
// 이전 페이지네이션 버튼 삭제
pagenationNumbers.innerHTML = '';
// 페이지네이션 버튼 생성
for (let i = 1; i <= pageCount; i++) {
pagenationNumbers.innerHTML += `<li li > <a href="">${i}</a></li > `; // 페이지네이션 버튼을 생성하고, 버튼의 숫자는 i 값으로 할당
}
// 페이지 버튼 선택
const numberButton = pagenationNumbers.querySelectorAll('a');
// 각 페이지 버튼을 클릭했을 때 발생하는 이벤트 등록
numberButton.forEach((item, index) => {
item.addEventListener('click', (e) => {
e.preventDefault();
// 페이지 번호를 인자로 받아, 해당 페이지에 해당하는 상품 목록 출력
displayRaw(index);
});
});
// 각 페이지에 해당하는 상품 목록 출력하는 함수
function displayRaw(index) {
let start = index * rowsPerPage; // 해당 페이지의 시작 인덱스 계산
let end = start + rowsPerPage; // 해당 페이지의 끝 인덱스 계산
// for문으로 rows 배열 내의 상품 목록 중 해당 페이지에 해당하는 상품 목록 출력
for (let i = 0; i < rowsCount; i++) {
if (i >= start && i < end) {
rows[i].style.display = 'block'; // 해당 페이지의 상품 목록은 보이도록 설정
} else {
rows[i].style.display = 'none'; // 해당 페이지가 아닌 상품 목록은 숨기도록 설정
}
}
// 페이지 버튼 활성화 표시를 위해 active 클래스 적용하고 이전 페이지 버튼의 활성화 클래스 제거
for (let nb of numberButton) {
nb.classList.remove('active');
}
numberButton[index].classList.add('active'); // 현재 페이지 버튼에 active 클래스 적용
}
displayRaw(0); // 첫 번째 페이지의 상품 목록을 먼저 보여줌
}
document.querySelector('.sorting-low-price-button').addEventListener('click', function () {
// 가격이 낮은 순서대로 정렬
jsonDataData = jsonData.data.sort((a, b) => a.price - b.price);
if (Array.isArray(jsonDataData)) {
innerData()
}
});
document.querySelector('.sorting-high-price-button').addEventListener('click', function () {
// 가격이 높은 순서대로 정렬
jsonDataData = jsonData.data.sort((a, b) => b.price - a.price);
if (Array.isArray(jsonDataData)) {
innerData()
}
});
//상품 목록 데이터가 배열일 경우, 상품 목록 UI 생성
if (Array.isArray(jsonDataData)) {
innerData()
}
} catch (error) {
console.log(error);
}
}
fetchData();
와우 프로젝트 진행하면서 깨달음까지!