어드민 페이지를 만들기 위해 jQuery, Bootstrap을 주로 사용합니다. 장점으로는 간단하고 빠르게 만들 수 있는 것 같습니다. 현재 기업협업 프로젝트를 진행 중인데 역시 jQuery, Bootstrap를 이용해서 만들고 있습니다. 하면서 기록하고 싶은 내용을 적을 계획입니다.
어드민페이지는 정보를 관리하는 페이지로 많이 쓰입니다. 많은 정보들을 테이블로 나열하는 경우가 많기 때문에 dataTable를 많이 사용하게 되는 것 같습니다.
<table
class="table"
id="datatable"
>
<thead>
<tr>
<th>columns_1</th>
<th>columns_2</th>
<th>columns_3</th>
<th>columns_4</th>
<th>columns_5</th>
<th>columns_6</th>
</tr>
</thead>
<tbody>
<tr>
<th>data_1</th>
<th>data_2</th>
<th>data_3</th>
<th>data_4</th>
<th>data_5</th>
<th>data_6</th>
</tr>
</tbody>
</table>
의 형태로 작성됩니다.
제가 기업협업중에 데이터를 받은 첫번째 방법으로는 api로 페이지 요청을 한 다음 데이터를 tbody안에 for문으로 날려주는 방식을 사용했습니다. 하지만 반응 속도가 느렸고, 한 페이지에 2만개가 넘는 데이터가 한번에 나와서 보기에도 불편했습니다. 요구사항에 pagination이 있었고 이를 구현하기 위해서는 다음 방법을 사용해야 했습니다.
다음으로 사용한 방법은 dataTable의 ajax를 사용하여 데이터를 불러왔습니다. 이전에는 api요청을 하면 페이지 전체의 정보를 불러와야했기 때문에 로딩 속도가 느렸지만 ajax를 사용하면 내가 지정한 범위안의 데이터만 따로 요청하여 원하는 데이터를 불러올 수 있기 때문에 이전보다 빠르게 데이터를 불러올 수 있었습니다.
let table;
$(document).ready(function () {
table = $("#datatable").DataTable({
ordering: true, // ordering 활성화
order: [[0, "asc"]], //0번째 컬럼 오름차순
paging: false, //페이징 기능 활성화. 기본이 true
pagingType: "full_numbers", // 페이징 버튼 타입 설정
pageLength: 40, // 한페이지에 보여주는 데이터 개수
responsive:true, // 스크립트를 추가하면 반응형으로 작동하게해줌
lengthChange: false, // pageLength 조절 불가하게 해줌
info:true, // 페이지 상태표시
autoWidth: false, //페이지 좌우 크기 조절시 테이블 크기 자동 적용
serverSide: true,
processing: true, // 서버와 통신 시 응답을 받기 전이라는 ui를 띄울 것인지 여부
ajax: {
url: url,
type: "GET",
dataType: "json",
data: {},
dataSrc: function (data) {
return data;
},
},
columns: [
{ data: "column_1" },
{
data: "column_2",
render: function (data, type, row) {
data = `<a href=/api>${data}</a>`;
return data;
},
},
{ data: "column_3" },
{ data: "column_4" },
],
columnDefs: [
{ targets: [2], visible: false },
{ targets: [3], visible: false },
],
});
기본적인 dataTable 옵션 구성입니다. 여기서 ajax를 위해 필요한 옵션은
serverSide: true,
processing: true,
입니다.
dataSrc부분에서 ajax로 받아온 데이터를 필터링해서 리턴할 수 있습니다.
columns는 테이블에 표시할 값을 의미합니다. 순서대로 값이 작성되기 때문에 컬럼명이랑 값을 잘 확인해서 적어야합니다. column_2처럼 태그를 추가할 수도 있습니다.
columnDefs는 각 컬럼마다 옵션을 추가할 수 있습니다. 데이터 정렬이라던가 검색을 위해서 값은 필요하지만, 테이블에 표시하고 싶지는 않을 경우에 사용했습니다.
ajax를 사용할 때 처음에는 serverSide: true
를 활성화하지 않고 ajax로 2만개의 데이터를 가져왔었습니다. 그리고 pagination과 search, ordering을 했습니다. 그런데 처음에 2만개의 데이터를 가져올 때 3~4초 정도 로딩이 필요했습니다. '만약 2만개가 아니라 20만개면 얼마나 오래 걸릴까?' 라는 생각이 문득 들었습니다.
데이터가 20만개라면 초반 로딩시간이 훨씬 길어지기에 결국은 불편하다는 것이 제 생각이었기 때문에, 이를 수정할 방법으로 한 페이지의 정보만을 가져오고 페이지 버튼을 누를 때마다, 검색값을 입력할 때 마다, 정렬 버튼을 누를 때마다, ajax 요청을 한 다음 한 페이지의 데이터만을 가져오는 것이 차후에는 가장 효율적이다고 생각했습니다. 하지만 저는 이를 해결할 방법을 못찾았었습니다.
기업 측에서도 저와 같은 의견이었고, 팀원들끼리 방법을 찾던도중 잊고있었던 serverSide가 이를 해결해 줄 수 있었습니다.
serverSide: true
를 활성화하고 다시 페이지를 로딩하면
api 주소 뒤에 많은 양의 req.query 값이 달려 나옵니다.
(출처: https://zamezzz.tistory.com/310)
이것은 query의 파라미터와 리턴값입니다. 이를 활용해서 res 값을
(참고: https://datatables.net/examples/data_sources/server_side)
사진과 같은 방식으로 내준다면 totalCount로 페이지의 버튼 개수를 추정할 수 있습니다.
페이지 마다 다른 값을 내어주기 위해서는 req.query.pageSize, req.query.start
값을 활용합니다.
let pageSize = Number(req.query.pageSize) || 10;
let skip = Number(req.query.start) || 0;
data.result = await User.find(query).skip(skip).limit(pageSize)
사진 처럼 skip과 limit를 사용하여 쿼리에서 값을 불러올 때 필터링을 할 수 있습니다.
skip은 시작할 위치를 정할 수 있습니다. 페이지 버튼을 누를때마다 req.query.start의 값이 바뀌는데 이를 활용해서 skip에 req.query.start을 정해준다면 시작하는 데이터의 값이 버튼마다 다르게 나오게 됩니다. limit는 몇 개를 출력할 것인지 정해줍니다.
검색 및 조회를 위해 작성했던 테이블과 id 값이 변경될 경우에 값을 구해서 draw()를 해주면 다시 ajax 요청을 해줍니다.
$("#id이름").change(function () {
let search_value = $("#id이름").val();
table.column(4).search(search_value).draw(); // 4번째 컬럼의 값으로 draw
});
그리고 api 문서에서 req.query.columns
을 확인해 보면 입력된 값이 req.query.columns[4].search.value
에 값이 들어와 있는 것을 확인할 수 있습니다.
이렇게 입력된 값을 활용해서 query에 저장한 다음
data.result = await User.find(query).skip(skip).limit(pageSize)
이와 같은 방식으로 입력해주면 query 조건에 맞게 필터링이 됩니다.
sort의 경우에는 ordering : true;
를 설정하고 컬럼을 누르면 req.query.order
에 값이 들어오는 것을 확인할 수 있습니다. req.query.order
안에 column, dir 두 개의 키가 있는데 column은 컬럼의 위치(0번째 컬럼, 1번째 컬럼..), dir은 asc, desc를 나타냅니다.
이를 활용해서 sort라는 변수에 값을 작성한 다음
data.result = await User.find(query).skip(skip).limit(pageSize).sort(sort)
로 작성하면 정렬이 된 데이터가 리턴됩니다.