(jQuery) Datatables 체크박스 필터 적용 메모

엽토군·2020년 12월 4일
0

1분 코드 스니펫

목록 보기
3/9
post-thumbnail

tl;dr

Datatables를 이용해서 뿌린 동적 테이블에 대충 이런 체크박스 필터를 붙인 메모이다.

외부 요소 정보를 datatable.ajax 데이터로 보내기

현재 이 datatable은 서버사이드 렌더링으로 자료를 비동기적으로 받아다가 사용한다.

<table> 태그 바깥의 <form id="filter"> 안에 있는 <input class="filter"> 체크박스들 상태가 변경될 때마다 그 값을 반영해서 datatable.draw()이 콜돼야 한다.

이 부분은 대충 이런 느낌으로 구현된다.

var dataTable = $('.datatable').DataTable({
  
    // #1
    processing: true,
    serverSide: true,
    ajax: {
        url: "/foo/bar/datatable",
        type: 'GET',
      
        // #2
        data: function (data) {

            // #3
            var filters = $('#filter').serializeArray();
            for (i = 0; i < filters.length; i++) {
                var filter = filters[i];
              
                // #4
                if (data[filter.name]) {
                    data[filter.name] += '|' + filter.value;
                } else {
                    data[filter.name] = filter.value;
                }
            }
        }
    }
});

// #5
$('#filter .filter').on('change keyup', function () {
    dataTable.draw();
});
  • #1: 서버사이드 렌더링을 위한 기본 필수 세팅
  • #2: 기본적으로 이 옵션이 서버에 전송될 data를 전처리한다. 문서를 보면 콜백에서 딱히 뭘 return할 필요는 없는 듯.
  • #3: 기왕 jQuery 쓰는거 .serializeArray()를 착취하기로 했다.
  • #4: 체크박스 필터란 "~한 것만 보기"로서 작동하는 것이 있고 "A 보기 / B 보기" 등 다지선다형으로 작동하는 것이 있다. 전자는 그냥 값을 그대로 넘기면 되지만 후자는 선택된 값들을 배열로 넘겨야 한다. 그래서 이 삽질을 추가함.
  • #5: 이런 사전 준비가 다 끝나면 실제 실행은 좀 맥없다.

아 참고로 서버쪽에서는 대충 이런 처리를 한다.

if (request()->has('ipsum')) {

    // JS에서 정의한 구분자로 분할해서 배열 만들어 WHERE IN 돌림
    $ipsums = explode('|', request()->input('ipsum'));
    $query->whereIn('lorem.ipsum', $ipsums);
}

체크박스들의 상태를 저장하기

위에서 구현한 필터박스는 매우 훌륭하게 동작했으나, 문제가 하나 있다. 새로고침을 하면 체크 상태가 모두 사라져 버린다. 이건 매우 불편한 일인데, 왜냐하면 위의 스크린샷처럼 간단하고 일회용적인 체크박스만 필요한 기능도 있지만, 체크박스의 체크 상태가 저장돼야 하는 꽤 복잡한 datatable도 있었기 때문이다.

DataTables 공식문서를 정말 뭐 빠지게 읽고 조사해서 알아낸 결론만 말하면, 이렇게 하면 된다.

var dataTable = $('.datatable').DataTable({

    // #1
    stateSave: true,
  
    // #2
    stateSaveParams: function (settings, data) {
        data.filters = $('#filter').serializeArray();
    },
    stateLoadParams: function (settings, data) {
        if (!data.filters) data.filters = $('#filter').serializeArray();
    },
  
    // #3
    stateLoaded: function (settings, data) {
        var filters = data.filters;
        for (i = 0; i < filters.length; i++) {
            var filter = filters[i];
          
            // #4
            var input = $('#filter__' + filter.name + '__' + filter.value);
            if (input) {
              
                // #5
                if (input.attr('type') == 'checkbox') {
                    input.trigger('click');
                }
            } 
        }
    }
});
  • #1: 이 옵션을 주면 상태를 저장한다. 여기서의 '상태'란 기본적으로는 이 DataTable() 인스턴스가 갖고 있던 정보들(검색어, 마지막으로 본 페이지 등)인데, 여기에 더하여 사용자가 원하는 것을 저장할 수 있다.
    그걸 어떻게 하느냐?
  • #2: 이렇게 한다.
    내가 이해한 게 맞다면 stateSaveParams().draw()가 콜되어서 화면을 새로 그리고 그 상태를 저장해야 할 때 실행되며, stateLoadParams()는 마지막에 저장해둔 상태를 지금 처음으로 불러와 사용해야 할 때 콜된다. 그 2개 내장메소드는, 별다른 리턴 없이 data 인자에 대한 조작만 추가하는 사용자 지정 함수가 있을 경우, 그걸 실행한 다음 최종적으로 자기 할 일을 한다. 맞나? 이 이상은 잘 모르겠음.
  • #3: stateLoaded()는 그야말로 상태가 완전히 다 로딩됐을 때 콜된다. 이 시점에서 data.filters에 저장해 둔 내용을 내가 알 수 있으므로, 가져다가 사용한다.
  • #4: 그 사용 요령은 엿장수 마음대로인데, 그래서 일단 나로서는 #filter 폼 안의 체크박스들에 #filter__lorem__1 같은 ID들을 달아놨다.
  • #5: 이제 어떤 데이터에 근거하여 어떤 체크박스를 처리하면 되는지 명확해졌으므로, 체크를 해주면 끝.

비고

사실 DataTables 위젯을 더 수려하게 확장하는 다른 방법이 많을 것이다. 하지만 그것까지는 PHP 개발자로서는 잘 못하겠고, 당장 떠오르는 방법만 가지고 이렇게 처리했다.

더 좋은 방법이 있다면 공유 좀 해 주십사 부탁드리는 바다.

profile
4년차 PHP 개발자입니다.

0개의 댓글