본문 바로가기

Project

애니리스트 페이지 - 장르 필터링 추가하기

 

애니메이션 페이지 최신순, 리뷰순 정렬도 다했고, 이제 검색 쿼리문 작성하고 프론트 페이지만 만들면 끝이였다.

맡은일을 빠르게 끝내고 휴가를 하루 냈는데.. 휴가를 낸 날에 페이지 구성요소와 새로운 기능이 추가되었다.

기존의 자유게시판은 따로 빠지고 장르별 필터링이 새롭게 들어왔다. 

7월3일까지 다 해야하는데 힘내보자.

 

일단 장르를 선택할 수 있는 박스를 하나 만들었다.

그리고 장르별로 무엇을 카테고리를 가져오고 애니 목록의 장르id들과 결합하여 장르별로 애니메이션이 보여지도록했다.

장르 선택시 보여질 애니메이션 컨트롤
let selectedGenres = [];

function filterAnimations() {
    let animations = document.querySelectorAll('.ani-info-container');

    if (selectedGenres.length === 0) {
        animations.forEach(function(animation) {
            animation.style.display = 'block';
        });
        return;
    }

    animations.forEach(function(animation) {
        let genreId1 = animation.querySelector('h4:nth-of-type(1)').textContent.trim();
        let genreId2 = animation.querySelector('h4:nth-of-type(2)').textContent.trim();

        let showAnimation = selectedGenres.includes(genreId1) || selectedGenres.includes(genreId2);

        if (showAnimation) {
            animation.style.display = 'block';
        } else {
            animation.style.display = 'none';
        }
    });
}

// 장르 체크박스 클릭 시 호출
document.addEventListener('DOMContentLoaded', function() {
    let genreCheckboxes = document.querySelectorAll('.genre-list');

    genreCheckboxes.forEach(function(checkbox) {
        checkbox.addEventListener('change', function() {
            let genreId = checkbox.id.replace('genre-', '');
            let index = selectedGenres.indexOf(genreId);

            if (checkbox.checked) {
                if (index === -1) {
                    selectedGenres.push(genreId);
                    // 여기에 페이지 네이션 함수를 넣어야한다.
                }
                console.log("선택된 장르 : " + selectedGenres);
            } else {
                if (index !== -1) {
                    selectedGenres.splice(index, 1);
                    console.log("선택 해제후 남은 장르 : " + selectedGenres);
                }
            }

            filterAnimations();
        });
    });
});

 

작업을 하다보니 페이지네이션이 이상하다는걸 깨달았다.


 

문제 1 . 이전페이지를 기억하지 못하는 문제

단순히 이전/다음 버튼을 누르면 보여질 요소를 바뀌게했더니 이전페이지를 기억하지 못하는 문제가 발생했다.

(7 → 8페이지에서 뒤로가기시 다시 1페이지로 돌아가는 상황)

 

이때 타임리프를 사용해서 페이지네이션처리를 할 수 있다는것을 알았는데 javascript로 해보고싶다는 오기가 생겼다.

직접 url에 파라미터를 주어서 페이지네이션 처리를 하면되지 않을까?( 잔머리만 돌아가는 나..) 

 

현재 위치를 기억할 객체를 새로 만들고 해당 url에 page라는 쿼리 파라미터를 설정하였다. 

그러고 history.replaceState를 사용하여 브라우저의 세션 기록을 업데이트하였다.

 

 

History: replaceState() method - Web APIs | MDN

The replaceState() method of the History interface modifies the current history entry, replacing it with the state object and URL passed in the method parameters. This method is particularly useful when you want to update the state object or URL of the cur

developer.mozilla.org

 

/* @ 페이지 네이션 */
let currentPage = 1;
let totalAni;
let totalPages;

function updateURL(page) {
    const url = new URL(window.location);
    url.searchParams.set('page', page);
    history.replaceState(null, '', url);
}

function renderPage(page) {
    const aniListContainer = document.getElementById('ani-list-container');
    const animations = aniListContainer.querySelectorAll('.ani-info-container');
    const buttonWrapper = document.getElementById('button-wrapper');

    currentPage = page;

    updateURL(page);

    buttonWrapper.innerHTML = '';

    for (let i = 1; i <= totalPages; i++) {
        const pageButton = document.createElement('li');
        pageButton.className = 'page-number page-btn';
        pageButton.innerText = i;
        pageButton.onclick = () => changePage(i);

        if (i === currentPage) {
            pageButton.style.backgroundColor = '#ff8b00';
            pageButton.style.color = 'white';
        }

        buttonWrapper.appendChild(pageButton);
    }

    animations.forEach(animation => {
        animation.style.display = 'none';
    });

    const start = (page - 1) * 12;
    const end = page * 12;
    for (let i = start; i < end && i < animations.length; i++) {
        animations[i].style.display = 'block';
    }
    window.scrollTo(0, 0);
}

function nextPage() {
    if (currentPage < totalPages) {
        renderPage(currentPage + 1);
    }
}

function prevPage() {
    if (currentPage > 1) {
        renderPage(currentPage - 1);
    }
}

function changePage(page) {
    renderPage(page);
}

document.addEventListener("DOMContentLoaded", function () {
    const aniListContainer = document.getElementById('ani-list-container');
    totalAni = aniListContainer.querySelectorAll('.ani-info-container').length;
    totalPages = Math.ceil(totalAni / 12);

    const urlParams = new URLSearchParams(window.location.search);
    const pageParam = parseInt(urlParams.get('page'), 10);

    if (!isNaN(pageParam) && pageParam > 0 && pageParam <= totalPages) {
        currentPage = pageParam;
    }

    renderPage(currentPage);
});

 

이제 장르별로 필터링했을때도 페이지네이션이 작동하게 바꿔야한다.

음..

두개의 함수를 합쳐야할꺼같은데 눈도 머리도 아프다.

블로그에 글 써놓고 비교하면서 붙여넣고 안되는부분은 콘솔을 찍으면서 하나씩 변경하였다.

// 전체 페이지네이션과 장르별 페이지네이션
let selectedGenres = [];
let currentPage = 1;
const animationsPerPage = 12;
let totalPages = 0;

function updateURL(page) {
    const url = new URL(window.location);
    url.searchParams.set('page', page);
    history.replaceState(null, '', url);
}

function filterAnimations() {
    let animations = document.querySelectorAll('.ani-info-container');
    let filteredAnimations = [];

    if (selectedGenres.length === 0) {
        filteredAnimations = Array.from(animations);
    } else {
        animations.forEach(function(animation) {
            let genreId1 = animation.querySelector('h4:nth-of-type(1)').textContent.trim();
            let genreId2 = animation.querySelector('h4:nth-of-type(2)').textContent.trim();

            let showAnimation = selectedGenres.includes(genreId1) || selectedGenres.includes(genreId2);
            if (showAnimation) {
                filteredAnimations.push(animation);
            }
        });
    }

    animations.forEach(animation => animation.style.display = 'none');

    let startIndex = (currentPage - 1) * animationsPerPage;
    let endIndex = startIndex + animationsPerPage;
    filteredAnimations.forEach((animation, index) => {
        if (index >= startIndex && index < endIndex) {
            animation.style.display = 'block';
        }
    });

    renderPagination(filteredAnimations.length);
    window.scrollTo(0, 0);
    updateURL(currentPage);
}

function renderPagination(totalAnimations) {
    let pageNumberBox = document.querySelector('.page-button-wrapper');
    pageNumberBox.innerHTML = '';

    totalPages = Math.ceil(totalAnimations / animationsPerPage);

    for (let i = 1; i <= totalPages; i++) {
        let pageButton = document.createElement('li');
        pageButton.textContent = i;
        pageButton.classList.add('page-number', 'page-btn');
        if (i === currentPage) {
            pageButton.style.backgroundColor = '#ff8b00';
            pageButton.style.color = 'white';
        }
        pageButton.addEventListener('click', function() {
            currentPage = i;
            filterAnimations();
        });
        pageNumberBox.appendChild(pageButton);
    }
}

function changePage(page) {
    if (page >= 1 && page <= totalPages) {
        currentPage = page;
        filterAnimations();
    }
}

function prevPage() {
    if (currentPage > 1) {
        currentPage--;
        filterAnimations();
    }
}

function nextPage() {
    if (currentPage < totalPages) {
        currentPage++;
        filterAnimations();
    }
}

document.addEventListener('DOMContentLoaded', function() {
    let genreCheckboxes = document.querySelectorAll('.genre-list');

    genreCheckboxes.forEach(function(checkbox) {
        checkbox.addEventListener('change', function() {
            let genreId = checkbox.id.replace('genre-', '');
            let index = selectedGenres.indexOf(genreId);

            if (checkbox.checked) {
                if (index === -1) {
                    selectedGenres.push(genreId);
                }
            } else {
                if (index !== -1) {
                    selectedGenres.splice(index, 1);
                }
            }

            currentPage = 1;
            filterAnimations();
        });
    });

    // 이전페이지 기억용
    const urlParams = new URLSearchParams(window.location.search);
    const pageParam = parseInt(urlParams.get('page'));
    if (!isNaN(pageParam) && pageParam > 0) {
        currentPage = pageParam;
    }

    filterAnimations();
});

 

복잡하게 생각헀는데 생각보다 간단한 문제였다

선택한 장르 id를 담을 배열을 하나더 만들고 그 배열에 담긴값들을 사용해서 총 페이지를 계산하면 되었다.

 장르를 여러개 선택했을때 페이지네이션이 생성되지 않은 문제도 해결!

 

 

이제 장르테이블에서 체크박스말고 장르 리스트를 눌렀을때도 바뀌게 해야지~

// 체크박스 리스트 클릭시 체크박스 활성화
function checkGenre(element) {
    const genreCheckbox = element.querySelector('input[type="checkbox"]');
    genreCheckbox.checked = !genreCheckbox.checked;
}

// HTML
 <div class="genre-container">
            <h3 class="genre-title">장르</h3>
            <div class="genre-list-container">
              <div th:each="genre: ${genreLists}" class="genre-title-list" onclick="checkGenre(this)">
                <input  type="checkbox" id="genre" class="genre-list" th:id="'genre-' + ${genre.id}"/>
                <label for="genre" class="check-genre" th:text="${genre.name}">
                </label>
              </div>
            </div>
          </div>

 

그렇게 장르별 필터링을 하고 최신순과 리뷰순 정렬을 클릭했는데 작동하지않았다.

최신순 리뷰순 클릭시 버튼 active 효과도 안먹힘..

 

문제 2. 장르별 필터링시 최신순/리뷰순 정렬이 안되는 문제

 

장르 선택/해제시 처리하는 함수를 따로 선언하고, 선택된 장르에따라 다시 필터링되도록 코드를 변경하였다.

 

function checkGenre(element) {
    const genreCheckbox = element.querySelector('input[type="checkbox"]');
    genreCheckbox.checked = !genreCheckbox.checked;

    const genreId = genreCheckbox.id.replace('genre-', '');
    const index = selectedGenres.indexOf(genreId);

    if (genreCheckbox.checked) {
        if (index === -1) {
            selectedGenres.push(genreId);
        }
    } else {
        if (index !== -1) {
            selectedGenres.splice(index, 1);
        }
    }

    currentPage = 1;
    filterAnimations();
}

잘 동작하기는 하는데 코드가 너무길다.

줄 일수 있을거같아서 코드를 줄여봤는데   체크박스 클릭시해도 체크가 안되는 문제가 발생했다.

아..

 

문제 3. 체크박스가 해제되지 않는 문제

더보기
function sortByAnimationId() {

    // const aniListContainer = document.getElementById('ani-list-container');

    let animationContainer = document.querySelectorAll("#data-animation-id+${animationId}")
    let animationId = animationContainer.replace('data-animation-id','');
    console.log(animationId)
    const aniListContainer = document.getElementById('ani-list-container');
    const arrayAnimations = Array.from(aniListContainer.getElementsByClassName('ani-info-container'));

    arrayAnimations.sort((a, b) => {

        let aAnimationId = parseInt(a.getAttribute('data-animation-id'), 10);
        let bAnimationId = parseInt(b.getAttribute('data-animation-id'), 10);

        return bAnimationId -aAnimationId;
    });


let aniArr = arrayAnimations.map(el => {
    console.log(el)
})


    aniListContainer.innerHTML = '';
    arrayAnimations.forEach(container => aniListContainer.appendChild(container));
}

// 리뷰순 정렬 함수
function sortByReviewCount() {

    const aniListContainer = document.getElementById('ani-list-container');
    const arrayAnimations = Array.from(aniListContainer.getElementsByClassName('ani-info-container'));

    arrayAnimations.sort((a, b) => {
        let aReviewCount = parseInt(a.getAttribute('data-review-count'), 10);
        let bReviewCount = parseInt(b.getAttribute('data-review-count'), 10);
        return bReviewCount - aReviewCount;
    });

    console.log(arrayAnimations.map(el => {
        console.log(el) //92개의 anumation이 다 들어옴
    }))

    aniListContainer.innerHTML = '';
    arrayAnimations.forEach(container => aniListContainer.appendChild(container));
}


let selectedGenres = [];
let currentPage = 1;
const animationsPerPage = 12;
let totalPages = 0;

function updateURL(page) {
    const url = new URL(window.location);
    url.searchParams.set('page', page);
    history.replaceState(null, '', url);
}

function filterAnimations() {
    let animations = document.querySelectorAll('.ani-info-container');
    let filteredAnimations = [];

    if (selectedGenres.length === 0) {
        filteredAnimations = Array.from(animations);
    } else {
        animations.forEach(function(animation) {
            let genreId1 = animation.querySelector('h4:nth-of-type(1)').textContent.trim();
            let genreId2 = animation.querySelector('h4:nth-of-type(2)').textContent.trim();

            let showAnimation = selectedGenres.includes(genreId1) || selectedGenres.includes(genreId2);
            if (showAnimation) {
                filteredAnimations.push(animation);
            }
        });
    }

    // 장르에 일치하는 애니가 없을 경우 보여줄 요소
    let emptyContainer = document.getElementById('empty-container');
    let pageBtnBox = document.getElementById('page-btn-box');
    let orderContainer = document.querySelector('.order-container');

    if (filteredAnimations.length === 0) {
        emptyContainer.style.display = "block";
        pageBtnBox.style.display = "none";
        orderContainer.style.display = "none";
    } else {
        emptyContainer.style.display = "none";
        pageBtnBox.style.display = "flex";
        orderContainer.style.display = "flex";
    }

    animations.forEach(animation => animation.style.display = 'none');

    let startIndex = (currentPage - 1) * animationsPerPage;
    let endIndex = startIndex + animationsPerPage;
    filteredAnimations.forEach((animation, index) => {
        if (index >= startIndex && index < endIndex) {
            animation.style.display = 'block';
        }
    });

    renderPagination(filteredAnimations.length);
    window.scrollTo(0, 0);
    updateURL(currentPage);
}

function renderPagination(totalAnimations) {
    let pageNumberBox = document.querySelector('.page-button-wrapper');
    pageNumberBox.innerHTML = '';

    totalPages = Math.ceil(totalAnimations / animationsPerPage);

    for (let i = 1; i <= totalPages; i++) {
        let pageButton = document.createElement('li');
        pageButton.textContent = i;
        pageButton.classList.add('page-number', 'page-btn');
        if (i === currentPage) {
            pageButton.style.backgroundColor = '#ff8b00';
            pageButton.style.color = 'white';
        }
        pageButton.addEventListener('click', function() {
            currentPage = i;
            filterAnimations();
        });
        pageNumberBox.appendChild(pageButton);
    }
    updateNavigationButtons();
}

function changePage(page) {
    if (page >= 1 && page <= totalPages) {
        currentPage = page;
        filterAnimations();
    }
}

function prevPage() {
    if (currentPage > 1) {
        currentPage--;
        filterAnimations();
    }
}

function nextPage() {
    if (currentPage < totalPages) {
        currentPage++;
        filterAnimations();
    }
}

// 페이지에 따라 버튼 disabled -> 이게 최선입니까 ????? 아니요
function updateNavigationButtons() {
    let firstPageBtn = document.getElementById('to-first');
    let prevPageBtn = document.getElementById('to-prev');
    let nextPageBtn = document.getElementById('to-next');
    let lastPageBtn = document.getElementById('to-end');

    if (currentPage === 1) {
        firstPageBtn.style.backgroundColor = 'lightgray';
        firstPageBtn.style.color = '#fff';
        prevPageBtn.style.backgroundColor = 'lightgray';
        prevPageBtn.style.color = '#fff';
        firstPageBtn.style.pointerEvents = 'none';
        prevPageBtn.style.pointerEvents = 'none';
    } else {
        firstPageBtn.style.backgroundColor = '';
        firstPageBtn.style.color = '';
        prevPageBtn.style.backgroundColor = '';
        prevPageBtn.style.color = '';

        firstPageBtn.style.pointerEvents = '';
        prevPageBtn.style.pointerEvents = '';
    }


    if (currentPage === totalPages) {
        nextPageBtn.style.backgroundColor = 'lightgray';
        nextPageBtn.style.color = '#fff';
        lastPageBtn.style.backgroundColor = 'lightgray';
        lastPageBtn.style.color = '#fff';
        nextPageBtn.style.pointerEvents = 'none';
        lastPageBtn.style.pointerEvents = 'none';
    } else {
        nextPageBtn.style.backgroundColor = '';
        nextPageBtn.style.color='';
        lastPageBtn.style.backgroundColor = '';
        lastPageBtn.style.color='';
        nextPageBtn.style.pointerEvents = '';
        lastPageBtn.style.pointerEvents = '';
    }
}



document.addEventListener('DOMContentLoaded', function() {
    let genreCheckboxes = document.querySelectorAll('.genre-list');

    genreCheckboxes.forEach(function(checkbox) {
        checkbox.addEventListener('change', function() {
            let genreId = checkbox.id.replace('genre-', '');
            let index = selectedGenres.indexOf(genreId);

            if (checkbox.checked) {
                if (index === -1) {
                    selectedGenres.push(genreId);
                }
            } else {
                if (index !== -1) {
                    selectedGenres.splice(index, 1);
                }
            }

            currentPage = 1;
            filterAnimations();
        });
    });

    // 이전페이지 기억용
    const urlParams = new URLSearchParams(window.location.search);
    const pageParam = parseInt(urlParams.get('page'));
    if (!isNaN(pageParam) && pageParam > 0) {
        currentPage = pageParam;
    }

    filterAnimations();

});

무식한 방법이지만 콘솔을 하나씩 찍어가면서 어떻게 랜더링되는지 어떤값을 가져오는지 어떤 오류가나는지 하나씩 확인하며 수정했다.

 

html에서 직접 버튼의 상태를 조작하던 기능을 js의 이벤트 리스너로 조작되게 변경하고,

DOMContentLoaded시의 이벤트 리스너의 실행 순서를 재조정하였다.

장르 배열에 값의 존재 여부에따라 애니메이션 목록을 생성하고

페이지네이션과 정렬순서에따라 필터링된 애니메이션이 보여지도록 하였다.

 

document.addEventListener('DOMContentLoaded', function() {
    const orderRecentBtn = document.getElementById('ordered-recent');
    const orderLikeBtn = document.getElementById('ordered-review');

    orderRecentBtn.classList.add('active');

    function handleButtonClick(event) {
        if (event.target === orderRecentBtn) {
            orderRecentBtn.classList.add('active');
            orderLikeBtn.classList.remove('active');
        } else if (event.target === orderLikeBtn) {
            orderLikeBtn.classList.add('active');
            orderRecentBtn.classList.remove('active');
        }
    }

    orderRecentBtn.addEventListener('click', handleButtonClick);
    orderLikeBtn.addEventListener('click', handleButtonClick);
});



// 체크박스 리스트 클릭시 체크박스 활성화
function checkGenre(element) {
    console.log(element)
    const genreCheckbox = element.querySelector('input[type="checkbox"]');
    genreCheckbox.checked = !genreCheckbox.checked;

    const genreId = genreCheckbox.id.replace('genre-', '');
    const index = selectedGenres.indexOf(genreId);

    if (genreCheckbox.checked) {
        if (index === -1) {
            selectedGenres.push(genreId);
        }
    } else {
        if (index !== -1) {
            selectedGenres.splice(index, 1);
        }
    }

    currentPage = 1;
    filterAnimations();
}


// 전체 페이지네이션과 장르별 페이지네이션 + 최신순, 리뷰순 합침
let selectedGenres = [];
let currentPage = 1;
const animationsPerPage = 12;
let totalPages = 0;

function updateURL(page) {
    const url = new URL(window.location);
    url.searchParams.set('page', page);
    history.replaceState(null, '', url);
}

function filterAnimations() {
    let animations = document.querySelectorAll('.ani-info-container');
    let filteredAnimations = [];

    if (selectedGenres.length === 0) {
        filteredAnimations = Array.from(animations);
    } else {
        animations.forEach(function(animation) {
            let genreId1 = animation.querySelector('h4:nth-of-type(1)').textContent.trim();
            let genreId2 = animation.querySelector('h4:nth-of-type(2)').textContent.trim();

            let showAnimation = selectedGenres.includes(genreId1) || selectedGenres.includes(genreId2);
            if (showAnimation) {
                filteredAnimations.push(animation);
            }
        });
    }

    let emptyContainer = document.getElementById('empty-container');
    let pageBtnBox = document.getElementById('page-btn-box');
    let orderContainer = document.querySelector('.order-container');

    if (filteredAnimations.length === 0) {
        emptyContainer.style.display = "block";
        pageBtnBox.style.display = "none";
        orderContainer.style.display = "none";
    } else {
        emptyContainer.style.display = "none";
        pageBtnBox.style.display = "flex";
        orderContainer.style.display = "flex";
    }

    animations.forEach(animation => animation.style.display = 'none');

    let startIndex = (currentPage - 1) * animationsPerPage;
    let endIndex = startIndex + animationsPerPage;
    filteredAnimations.forEach((animation, index) => {
        if (index >= startIndex && index < endIndex) {
            animation.style.display = 'block';
        }
    });

    renderPagination(filteredAnimations.length);
    window.scrollTo(0, 0);
    updateURL(currentPage);
}

function renderPagination(totalAnimations) {
    let pageNumberBox = document.querySelector('.page-button-wrapper');
    pageNumberBox.innerHTML = '';

    totalPages = Math.ceil(totalAnimations / animationsPerPage);

    for (let i = 1; i <= totalPages; i++) {
        let pageButton = document.createElement('li');
        pageButton.textContent = i;
        pageButton.classList.add('page-number', 'page-btn');
        if (i === currentPage) {
            pageButton.style.backgroundColor = '#ff8b00';
            pageButton.style.color = 'white';
        }
        pageButton.addEventListener('click', function() {
            currentPage = i;
            filterAnimations();
        });
        pageNumberBox.appendChild(pageButton);
    }
    updateNavigationButtons();
}

function changePage(page) {
    if (page >= 1 && page <= totalPages) {
        currentPage = page;
        filterAnimations();
    }
}

function prevPage() {
    if (currentPage > 1) {
        currentPage--;
        filterAnimations();
    }
}

function nextPage() {
    if (currentPage < totalPages) {
        currentPage++;
        filterAnimations();
    }
}

function updateNavigationButtons() {
    let firstPageBtn = document.getElementById('to-first');
    let prevPageBtn = document.getElementById('to-prev');
    let nextPageBtn = document.getElementById('to-next');
    let lastPageBtn = document.getElementById('to-end');

    if (currentPage === 1) {
        firstPageBtn.style.backgroundColor = 'lightgray';
        firstPageBtn.style.color = '#fff';
        prevPageBtn.style.backgroundColor = 'lightgray';
        prevPageBtn.style.color = '#fff';
        firstPageBtn.style.pointerEvents = 'none';
        prevPageBtn.style.pointerEvents = 'none';
    } else {
        firstPageBtn.style.backgroundColor = '';
        firstPageBtn.style.color = '';
        prevPageBtn.style.backgroundColor = '';
        prevPageBtn.style.color = '';

        firstPageBtn.style.pointerEvents = '';
        prevPageBtn.style.pointerEvents = '';
    }

    if (currentPage === totalPages) {
        nextPageBtn.style.backgroundColor = 'lightgray';
        nextPageBtn.style.color = '#fff';
        lastPageBtn.style.backgroundColor = 'lightgray';
        lastPageBtn.style.color = '#fff';
        nextPageBtn.style.pointerEvents = 'none';
        lastPageBtn.style.pointerEvents = 'none';
    } else {
        nextPageBtn.style.backgroundColor = '';
        nextPageBtn.style.color = '';
        lastPageBtn.style.backgroundColor = '';
        lastPageBtn.style.color = '';
        nextPageBtn.style.pointerEvents = '';
        lastPageBtn.style.pointerEvents = '';
    }
}

function sortByAnimationId() {
    let animations = Array.from(document.querySelectorAll('.ani-info-container'));
    animations.sort((a, b) => {
        return parseInt(b.getAttribute('data-animation-id')) - parseInt(a.getAttribute('data-animation-id'));
    });
    updateAnimationOrder(animations);
}

function sortByReviewCount() {
    let animations = Array.from(document.querySelectorAll('.ani-info-container'));
    animations.sort((a, b) => {
        return parseInt(b.getAttribute('data-review-count')) - parseInt(a.getAttribute('data-review-count'));
    });
    updateAnimationOrder(animations);
}

function updateAnimationOrder(sortedAnimations) {
    let container = document.querySelector('.ani-list-container');
    container.innerHTML = '';
    sortedAnimations.forEach(animation => {
        container.appendChild(animation);
    });
    currentPage = 1;
    filterAnimations();
}

document.addEventListener('DOMContentLoaded', function() {
    let genreCheckboxes = document.querySelectorAll('.genre-list');

    genreCheckboxes.forEach(function(checkbox) {
        checkbox.addEventListener('change', function() {
            let genreId = checkbox.id.replace('genre-', '');
            let index = selectedGenres.indexOf(genreId);

            if (checkbox.checked) {
                if (index === -1) {
                    selectedGenres.push(genreId);
                }
            } else {
                if (index !== -1) {
                    selectedGenres.splice(index, 1);
                }
            }

            currentPage = 1;
            filterAnimations();
        });
    });

    const urlParams = new URLSearchParams(window.location.search);
    const pageParam = parseInt(urlParams.get('page'));
    if (!isNaN(pageParam) && pageParam > 0) {
        currentPage = pageParam;
    }

    filterAnimations();
});

 

 

이제 모든 기능이 잘 작동한다.

 

마지막으로 애니가 없을때 건의하기 버튼도  추가

 


📝  오늘의 생각

잘작동하는것을 확인하고 쉬고있는데 백엔드 코드 완전 비효율적으로 작성했다는걸 알았다.

처음에는 통신비용을 생각해서 무한스크롤로 데이터를 일부분만 넘기는 방식을 생각했는데 

어느순간 '한번의 통신으로 처리하자' 라는 생각으로 바뀌어있었다.

지금이야 데이터가 적으니까 전부 보내도 속도저하가 없었지만 실제 기업이였다면 비용이랑 속도 문제가 발생했을거였다.

 

타임리프로 페이지네이션을 처리하는 방법이있었는데 이게 무슨 고집이였을까

백에서 페이지네이션을 처리하고 프론트에서 그대로 가져와서 사용하면 편했을것을 오늘도 하나 배워간다.