-
코로나19 백신 접종 현황 차트 페이지 만들기 - (10) search 페이지, datatable, 검색 기능Node.js/예제 2021. 6. 5. 15:35
1. search 페이지
테이블 라이브러리를 활용하여 엘라스틱서치 인덱스 데이터를 테이블로 시각화하여 제공하는 페이지다. country-vaccinations 인덱스(country_vaccinations.csv 데이터)를 사용하였고, 일자별 접종 기록을 국가별로 제공해준다. 상단 Country search 입력란에 국가명을 입력하면 해당 국가에 대한 데이터가 조회된다.
table.ejs
<%- include('header') %> <%- include('dt') %> </head> <body> <div class="container"> <%- include('navbar') %> <div class="tablediv"> <table id="table" class="display" style="width: 100%"> <thead> <tr id="tableTr"></tr> </thead> </table> </div> </div> <script src="js/datatable.js"></script> <script> const ulInnerHtml = document.getElementById("navBar").innerHTML; const newBtns = ` <div class="country-search-area"> <input class="country-input" type="input" id="countryFilter" onclick="clearInput(this);"> <label class="label-text">Country search</label> </div> `; document.getElementById("navBar").innerHTML = ulInnerHtml + newBtns; getCountryList(); drawDataTable("South Korea"); </script> </body> </html>
search 페이지에 대한 frontend 코드는 위와 같다. 공통 헤더와 datatable 모듈, 공통 내비게이션을 불러온다. 내비게이션에는 국가명 검색 기능을 위한 검색창을 추가해주었다. 페이지 시작 시 자동 완성을 위해 국가 리스트를 불러오는 함수인 getCountryList를 호출하고, 테이블을 생성해주는 drawDataTable 함수도 호출한다. drawDataTable은 국가명을 파라미터로 받는데, 첫 페이지 시작 시에는 기본적으로 한국에 대한 데이터가 로딩될 수 있게 'South Korea'를 인자로 넣었다.
2. 서버 코드(table.js)
router.post('/records', async (req, res) => { const { param } = req.body; const query = ` SELECT date, country, daily_vaccinations, daily_vaccinations_per_million, vaccines FROM "country-vaccinations" WHERE country='${param}' `; try { const data = await getDataUsingSql(query, 10000); res.json(data) } catch (err) { console.error(err); } });
테이블을 그대로 보여주기 때문에 쿼리는 복잡하지 않다. 테이블 페이지에서 보여줄 컬럼인 날짜(date), 국가(country), 일일 백신 접종자수(daily_vaccinations), 일일 백신 접종률(daily_vaccinations_per_million)을 select절에서 지정하고, where절에서는 검색어로 입력되는 국가명을 받아서 필터링할 수 있게 하였다. 검색창에 입력된 키워드는 ajax에서 파라미터로 전달받는다.
조회 대상이 많아질 수도 있기 때문에 getDataUsingSql 함수에 두 번째 파라미터인 개수 데이터를 지정하였다. 디폴트값이 1000이기 때문에 개수를 지정하지 않으면 최대 1000개만 조회된다. 그 이상의 양을 조회할 필요가 다면 별도로 최대 조회 데이터 수를 지정해주어야 한다.
3. datatable
datatable은 테이블 UI를 위한 라이브러리다. 데이터를 테이블 형태로 표현하는 데에 유용하며, 페이지네이션, 결과 내 검색, 정렬 기능 등을 기본적으로 제공해주기 때문에 사용하기에도 편리하다. datatable 홈페이지에서 자세한 사용법과 예제를 확인할 수 있다. 여기에서는 관련 cdn을 dt.ejs에서 불러와서 사용하였다.
datatable.js - drwsDataTable()
function drawDataTable(param) { $.ajax({ url: "/table/records", type: "POST", data: { param }, dataType: "json", success: function (result) { const { columns, rows } = result; let colHtml = ""; const cols = columns.map(col => { const colStr = col.name; const colName = colStr.split("_").map(s => s.replace(s[0], s[0].toUpperCase())).join(" "); colHtml += `<th>${colName}</th>`; return { data: colName }; }); document.getElementById("tableTr").innerHTML = colHtml; const data = rows.map(row => { const obj = {}; for (let i = 0; i < row.length; i++) { obj[cols[i].data] = i === 0 ? row[i].replace("T00:00:00.000Z", "") : row[i]; } return obj; }); $(document).ready(function () { $("#table").dataTable({ data, columns: cols, destroy: true, columnDefs: [ { width: "15%", "targets": 0, className: "text-center" }, { width: "17%", "targets": 1, className: "text-center" }, { width: "15%", "targets": 2, className: "text-center", render: function (data) { return data ? addComma(data) : data; } }, { width: "18%", "targets": 3, className: "text-center", render: function (data) { return data ? addComma(data) : data; } }, { width: "45%", "targets": 4 }, ], order: [[0, "desc"]] }); }); }, error: function (request, status, error) { console.error(error); } }) }
ajax 요청 시 함수의 인자로 받아온 param 값을 서버로 전달해준다. 이 값은 검색 입력창에 입력한 키워드며, 서버의 쿼리 where절에서 조건으로 처리된다. 요청에 대해 받아온 데이터 값을 datatable에서 요구하는 형태로 변환해준다. 테이블은 $("#table").dataTable({.... 내에서 생성해준다. 이 구절 내부 키의 값으로 각각의 값들을 입력해주면 된다. colomns는 컬럼명을 지정해준다. 컬럼으로 지정할 단어들이 담긴 배열을 값으로 지정해준다. 실제 데이터들은 data의 값으로 전달해주면 된다. { 컬럼명: 값, 컬럼명: 값, ... } 의 형태로 된 데이터들이 담긴 배열이다. 그리고 각 컬럼에 대한 정렬, width 등의 옵션은 columnDefs에서 지정해주면 된다. 그리고 order를 통해 기본 sorting 컬럼을 지정해줄 수 있다.
destroy는 테이블을 재초기화할 필요가 있을 때 true로 지정해주어야 한다. 검색 결과를 표시할 때 페이지 리로딩 과정 없이 ajax의 요청 결과로 테이블 내용이 바뀌어야 하는데, destroy 과정 없이 기존 테이블이 있는 상태에서 테이블 초기화를 시도할 경우 datatable은 초기화 에러를 발생시킨다. destroy의 값을 true로 지정한다면 이 에러는 발생하지 않는다.
4. 검색 기능과 검색어 자동 완성
검색창에 국가명을 입력하면 그에 대한 데이터를 테이블에서 보여준다. 그러나 사용자 입장에서는 어떤 국가들이 어떤 이름으로 들어가있는지 알 수 없기 때문에 자동완성을 통해 입력 시 리스트를 띄워주면 사용하기에 더 편하다. 입력 input에 jQuery의 autocomplete를 지정해두면 위와 같이 글자 입력시 그 글자가 포함된 검색어 리스트를 보여주게 된다.
과정은 다음과 같다. 1) 페이지 실행 시 getCountryList 함수 호출하고, 2) /countries 라우터로 ajax 요청한 후, 3) 요청에 대한 결과값 전달받은 국가 리스트를 autocomplete의 리스트에 적용한다.
table.js - post /countries
router.post('/countries', async (req, res) => { const query = ` SELECT country, COUNT(*) FROM "country-vaccinations" GROUP BY country `; try { const data = await getDataUsingSql(query); const resultData = data.rows.map(el => el[0]); res.json(resultData) } catch (err) { console.error(err); } });
datatable.js - getCountryList()
function getCountryList() { $.ajax({ url: "/table/countries", type: "POST", dataType: "json", success: function (result) { $("#countryFilter").autocomplete({ source: result, minLength: 2, select: function (e, data) { drawDataTable(data.item.value); }, }) }, error: function (request, status, error) { console.error(error); } }) }
getCountryList에서 ajax 요청을 하면 전체 국가 리스트를 서버에서 전달해준다. 이 리스트를 autocomplete의 source의 값으로 전달해준다. minLength를 2로 지정해주었는데, 배열의 길이가 190이 넘어가기 때문에 기본 1인 상태에서는 한 글자만 입력해도 그 글자가 포함된 모든 국가가 리스트에 뜨게 된다. 따라서 글자 2개를 입력했을 때 2개의 글자고 시작되는 국가명만 리스트에 뜰 수 있도록 제한을 두었다.
그리고 select의 값으로 테이블을 생성하는 함수를 값으로 지정하여 리스트에서 값을 선택했을 때 검색 결과가 테이블에 바로 뜨드록 하였다.
'Node.js > 예제' 카테고리의 다른 글
코로나19 백신 접종 현황 차트 페이지 만들기 - (9) map 페이지와 highmap을 활용한 지도 차트 (0) 2021.06.04 코로나19 백신 접종 현황 차트 페이지 만들기 - (8) heatmap (0) 2021.06.04 코로나19 백신 접종 현황 차트 페이지 만들기 - (7) line chart (0) 2021.06.03 코로나19 백신 접종 현황 차트 페이지 만들기 - (6) column chart (0) 2021.06.03 코로나19 백신 접종 현황 차트 페이지 만들기 - (5) highchart 라이브러리와 piechart (1) 2021.06.01