본문 바로가기

JavaScript

Grid 라이브러리-Datatables 사용법/예제

최근 사용하게 된 datatables 라이브러리에 대한 약간의 설명을 공유하고자 합니다.

datatables는 데이터 그리드를 다루는 라이브러리로 '이 기능이 있었으면' 하는 부분은 거의 갖추고 있습니다. 

한글로 된 자료는 거의 기본옵션에 대한 설명밖에 없어 고생했는데(ㅠㅠ), 실제 구현했던 기능들 위주로 설명할 예정입니다. 


Datatables 는 MIT 라이센스로 무료입니다. 


DEMO : https://saintsilver.github.io/datatables-ex/ 

기본 사용

음.. 이건 그냥 스크린샷으로 대체합니다.
공식홈페이지에 들어가시면 메인페이지에 등장합니다. 


윗 스크린샷에서 설명이 생략된 #myTable 은 아래와 같은 구조로 만드시면 되고, 

서버사이드로 데이터를 처리하여 데이터테이블을 만들 시 <tbody>를 선언하시고 실제로 값을 넣으시면 됩니다.

저는 ajax로 처리할 예정이라서 <thead>만 사용했습니다. 


공식홈페이지에선 데이터가 100,000건 이상이면 서버사이드로 처리하라고 권장하고 있습니다. 


<table id="myTable">
    <thead>
        <tr>
            <th>컬럼1</th>
            <th>컬럼2</th>
            <th>컬럼3</th>
        </tr>
    </thead>
</table>
cs

Ajax

아래와 같이 사용합니다. 기본은 GET 방식입니다. 
데이터를 받아오고, columns로 json의 키 값에 맞춰 선언해 줍니다. 
data를 4개 선언하셨으면, HTML의 <table>에도 4개의 컬럼이 있어야 됩니다. 

 var table = $('#myTable').DataTable({
     ajax: {
        'url':'MOCK_DATA.json'
        //'type': 'POST',
        'dataSrc':''
     },
    columns: [
        {"data""id"},
        {"data""first_name"},
        {"data""last_name"}, 
        {"data""email"}
    ]
});
cs

주의하실 점은, 위의 dataSrc 라는 옵션입니다. 
datatables 가 Ajax로 데이터를 가져올 때는 기본적으로 아래와 같이 최상위에 "data" 라는 키를 가진 형태이어야 합니다.

{
  "data": [
    {
      "id""1",
      "name""Tiger Nixon",
      "position""System Architect",
      "salary""$320,800",
      "start_date""2011/04/25",
      "office""Edinburgh",
      "extn""5421"
    },
    {
      "id""2",
      "name""Garrett Winters",
      "position""Accountant",
      "salary""$170,750",
      "start_date""2011/07/25",
      "office""Tokyo",
      "extn""8422"
    }
....
cs

즉 서버단에서 데이터를 던져줄 때 "data" 키로 전달하던가
dataSrc 옵션을 사용해 키 값을 직접 변경하셔야 합니다.
제가 사용할 데이터는 이중구조가 아니기 때문에 ""로 처리했습니다. (제가 사용한 데이터)
여기서 한 30분 삽질한 것 같습니다.. ㅠㅠ

스타일

기본 스타일도 상당히 깔끔하긴 하지만 부트스트랩의 테이블처럼 클래스명을 통해 간단한 스타일을 줄 수 있습니다.
hover, stripe, compact 등등 여러 옵션이 있구요, 클래스명에 display를 사용하시면 stripe hover order-column row-border 옵션이 모두 사용됩니다. 

이외에도 추가로 css와 js파일을 추가해서 아래와 같이 가져다 쓸 수 있습니다. 

https://datatables.net/examples/styling/material.html

https://datatables.net/examples/styling/uikit.html

언어 변경

Loading.. 이라든가 Show 10 entries 와 같은 텍스트들 전부 한글로 변경할 수 있습니다. 
아래와 같이 선언할 때 옵션을 주시면 됩니다.
 var table = $('#myTable').DataTable({
    "language": {
        "emptyTable""데이터가 없어요.",
        "lengthMenu""페이지당 _MENU_ 개씩 보기",
        "info""현재 _START_ - _END_ / _TOTAL_건",
        "infoEmpty""데이터 없음",
        "infoFiltered""( _MAX_건의 데이터에서 필터링됨 )",
        "search""에서 검색: ",
        "zeroRecords""일치하는 데이터가 없어요.",
        "loadingRecords""로딩중...",
        "processing":     "잠시만 기다려 주세요...",
        "paginate": {
            "next""다음",
            "previous""이전"
        }
    },
});
cs


옵션이 엄청나게 많은데, 이 정도만 바꾸셔도 영어는 안 보일 겁니다. 

아래에서 더 찾아보실 수 있습니다.

https://datatables.net/reference/option/language

셀 데이터 커스텀

지금은 columns 옵션에서 data: key값을 통해 정직한 데이터만 뿌려주고 있습니다.
약간의 수정을 통해 만약에 돈과 관련된 컬럼이라면 '\' 혹은 '-원' 같이 글자를 붙여주거나
url주소라면 <a>태그로 변경하거나 다운로드 처리를 하고,
다른 컬럼의 값과 혼용해서 사용하는 등등의 처리를 할 수 있겠습니다. 

아래와 같이 추가로 선언해 처리하시면 됩니다.
row['컬럼명'] 을 사용해 동일한 라인에 위치한 데이터의 다른 값을 사용할 수도 있습니다. 
....생략
    columns: [
        {"data""id"},
        ....
        {"data""url",
            "render"function(data, type, row){
                if(type=='display'){
                    data = '<a href="'+ data + '">' + 링크로 이동 + '</a>';
                }
                return data;
            }
    ]
....
    }},
cs

반응형

가장 인상깊은 부분입니다. 아래와 같이 기기를 넘나들며 완벽하게 대응할 수 있습니다. 


추가적으로 아래 두 개의 파일이 더 필요합니다.

//cdn.datatables.net/responsive/2.2.3/css/dataTables.responsive.css


그리고 선언할 때 옵션 하나만 더해주시면 됩니다.

$('#myTable').DataTable( {
    responsive: true
} );
cs


다만 테이블 크기가 처음 켜질 때의 브라우저 크기에 맞춰 고정되는 것으로 보입니다. 

그래서 저는 table 자체에 추가로 width: 100% 를 주고 사용합니다. 

컬럼별 검색

datatables의 검색은 모든 컬럼을 대상으로 합니다. 강력하고 심플하고 편하긴 하지만 컬럼별로 검색할 수 있으면 더 좋지 않을까요? <select> 태그를 통해 선택한 컬럼에서만 검색이 되도록 추가해 봅시다.

직접 HTML에 선언하셔도 되지만, 저는 검색 바로 옆에 달고 싶어서 해당 위치에 직접 밀어넣었습니다.
그리고 반복문으로 컬럼명에 따른 <option>도 추가했습니다.

    /* Column별 검색기능 추가 */
    $('#myTable_filter').prepend('<select id="select"></select>');
    $('#myTable > thead > tr').children().each(function (indexInArray, valueOfElement) { 
        $('#select').append('<option>'+valueOfElement.innerHTML+'</option>');
    });
cs


그리고 아래와 같이 원래 있던 검색기능을 unbind 한 뒤에, select 옵션으로 선택된 컬럼만 검색하도록 다시 이벤트를 추가했습니다. $('.dataTables_filter input') 은 검색 input 이고, draw()는 키가 눌릴 때마다 테이블을 다시 그려 줍니다.


(이렇게 변경됐습니다)


    $('.dataTables_filter input').unbind().bind('keyup'function () {
        var colIndex = document.querySelector('#select').selectedIndex;
        table.column(colIndex).search(this.value).draw();
    });
cs

날짜 기간 검색

여기에 기간별로 데이터를 조회할 수 있는 기능을 추가해 보겠습니다. 
이것도 셀렉트박스로 연,월 처리할 수 있지만, 그냥 input 태그로 처리하기로 합니다. 
아래와 같이 ~부터 ~까지를 위한 input 태그 2개를 밀어넣습니다. 
    $('#myTable_filter').prepend('<input type="text" id="toDate" placeholder="yyyy-MM-dd"> ');
    $('#myTable_filter').prepend('<input type="text" id="fromDate" placeholder="yyyy-MM-dd">~');
cs


여기가 좀 까다로운데요, datatable을 선언하기 전에 search 기능에 약간 손을 봐 줍시다.

조건이 4개인 이유는, ~부터 혹은 ~까지 중 하나만 입력해도 검색이 이루어지게 하기 위함입니다.

https://datatables.net/manual/plug-ins/search 여기를 참고하실 수 있습니다.


true가 리턴되면 검색이 이뤄지구요, false가 리턴되면 무시합니다. 

$.fn.dataTable.ext.search.push(
    function(settings, data, dataIndex){
        var min = Date.parse($('#fromDate').val());
        var max = Date.parse($('#toDate').val());
        var targetDate = Date.parse(data[5]);
 
        if( (isNaN(min) && isNaN(max) ) || 
            (isNaN(min) && targetDate <= max )|| 
            ( min <= targetDate && isNaN(max) ) ||
            ( targetDate >= min && targetDate <= max) ){ 
                return true;
        }
        return false;
    }
)
cs


분명히 맞게 쓴 것 같은데 작동을 안해서 삽질을 했는데, 위에서 컬럼별 검색기능을 추가하면서 검색기능이 겹쳤습니다. 

아래와 같이 날짜를 입력하는 input 에만 이벤트를 리바인딩 처리했습니다.


$('#toDate, #fromDate').unbind().bind('keyup',function(){
    table.draw();
})
cs

footer와 summary

검색이 이루어지면 표 아래 요약본이 나오면 좋겠다고 합니다. 
예를 들어 금액이라면 금액총합이 나와야 합니다. 모두 나와야 하는 것은 아니고 검색을 통해 필터링된 데이터에 대한 통계가 나와야 합니다. 

그럼 <table> 태그로 가서, 우리가 갖고 있지 않은 <tfoot> 태그를 선언해 줍니다. 
그리고 <tr> 아래 <th>를 컬럼 수만큼 선언해주시는데 저는 8개 컬럼 중 2개의 컬럼만 필요해서 아래와 같이 처리했습니다. 
<tfoot>
    <tr>
        <th colspan="2" style="text-align:right;white-space:nowrap;">TOTAL : </th>
        <th colspan="6" style="text-align:left;white-space:nowrap;"></th>
    </tr>
</tfoot>
cs

그리고, datatable의 옵션을 설정할 때, 아래와 같이 "footerCallback" 옵션과 콜백메서드를 사용합니다. 
아래 column() 부분은 차례대로 컬럼(인덱스 말고 컬럼명으로도 사용가능)과 사용할 데이터 옵션입니다. 
search: 'applied' 라고 설정하면 필터링된 데이터만 사용하구요. 
page: 'current' 라고 설정하면 현재 페이지의 데이터만 사용하는 등의 옵션을 줄 수 있습니다.

서버사이드로 처리하신다면 좀 더 손댈 부분이 많겠네요.

아래에서 전체 옵션을 확인하세요. 

        /* Footer에 금액총합 구하기,
            * filtered data 총합만 계산하도록 함.*/
        "footerCallback":function(){
            var api = this.api(), data;
            var result = 0;
            api.column(7, {search:'applied'}).data().each(function(data,index){
                result += parseFloat(data);
            });
            $(api.column(3).footer()).html(result.toLocaleString()+'원');
        },
cs


.toLocaleString()은 천단위로 컴마를 찍어줍니다. 


그리고 해당 콜백메서드는 5개의 파라미터를 받을 수 있습니다. 저는 사용하지 않았는데 아래에서 확인해 보세요.

https://datatables.net/reference/option/footerCallback


아래와 같이 필터링 된 데이터의 금액총합을 구했습니다.


(아름답습니다.. )

엑셀Excel로 Export

데이터를 엑셀로 빼고 싶다고 요청이 추가됐습니다. 
그것도 필터링 된 데이터만 파일로 다운로드 받아졌으면 좋겠다고 하네요. 

그런데 이 기능 또한 datatables는 가지고 있습니다. 
이 기능을 보고 얼마나 감동했는지 모릅니다 ㅠ_ㅠ 
  1. 클립보드로 복사하기
  2. CSV 파일
  3. Excel 파일
  4. PDF 파일
  5. 프린트
위 다섯 가지의 기능을 제공합니다. 


다만 저 기능을 다 가져오려면 추가되는 파일이 좀 많은데요, 저는 CSV 파일로만 export 하는 걸로 하겠습니다. 

그럼 아래 두 개만 추가하시면 됩니다.

https://cdn.datatables.net/buttons/1.5.2/js/dataTables.buttons.min.js
https://cdn.datatables.net/buttons/1.5.2/js/buttons.html5.min.js


그리고 아래와 같이 사용합니다. 


$(document).ready(function() {
    $('#myTable').DataTable( {
        dom: 'Blfrtip',
        buttons: [{
            extend: 'csvHtml5',
            text: 'Export CSV',
            footer: true,
            className: 'exportBtn'
        }]
    } );
} );
cs


이렇게 선언하는 것만으로 버튼을 누르자마자 footer가 포함된 데이터가 (그것도 필터링된!) csv 파일로 다운로드됩니다.

dom 옵션의 Blfrtip 은 단어가 아니라, 알파벳 하나하나에 의미가 있어 옵션을 주는 방식입니다.

아래와 같은데요, 비워놓을시 디폴트값은 lfrtip 입니다. 여기에 Buttons의 B 가 추가되는 것이라고 보면 됩니다. 

순서를 바꾸면 위치도 바꿀 수 있습니다. 예를 들어 f 를 p 바로 이전에 두면 페이징 위에 필터링 input이 위치합니다. 

  • l - length changing input control
  • f - filtering input
  • t - The table!
  • i - Table information summary
  • p - pagination control
  • r - processing display element

아래와 같이 필터링 된 검색결과에서 엑셀버튼을 누르면, 


다운로드된 파일에서 필터링 된 결과와 동일한 데이터를 담은 csv 파일을 얻을 수 있습니다. 

새로고침

사용자와 상호작용하며 데이터가 실시간으로 바뀌어야 할 때도 있죠. 
간단한 예를 들어 승인버튼 같은게 있겠네요. 
데이터 업데이트를 하시고 아래와 같이 사용해 주세요. 

1
2
/* 페이지 고정 */
$('#dataList').DataTable().ajax.reload(nullfalse);
cs

기타 기능

이 외에도 하나의 포스팅으로 설명하기 어려운 만큼 다양한 옵션이 있습니다. 

orderMulti: true 를 설정하면 쉬프트키를 이용해 여러 컬럼을 동시에 정렬할 수 있구요. 

order : [[index, 'desc']] 와 같이 설정하면 처음 datatable이 그려질 때 선택한 컬럼이 역순으로 정렬됩니다.

헤더/컬럼/푸터 고정, Row grouping, 리오더, 스크롤러 등..


이번에 사용하진 않았지만 Editor 기능을 통해 테이블에서 CRUD 도 가능합니다. (이 기능은 유료입니다)


아래 링크에서 포스팅에 사용한 코드를 보실 수 있습니다. 

CODE : https://github.com/SaintSilver/datatables-ex

DEMO : https://saintsilver.github.io/datatables-ex/