B1-4 Column Filtering - Filter Action 응용 자동 필터 구현
들어가며
B1-1, B1-2 강좌에서 Filter와 FilterAction의 기본적인 사용방법을 배웠습니다.
이 강좌에서는 Filter
와 FilterAction
을 응용하여 엑셀의 자동 필터와 유사한 UI로 구현하는 방법을 알아봅시다.
이론
- 컬럼의 Filter Icon를 클릭하였을 때 다음의 조건이 모두 만족하면 Filter 목록이 표시되지 않고 바로 GridBase.onFilterActionClicked() 콜백이 발생합니다.
- hidden속성이 false인 필터가 존재하지 않음
- 유일한 FilterAction
- onFilterActionClicked에서 전달되는 x,y 좌표를 기준으로 별도의 division(divAutoFilter)을 표시합니다.
- divAutoFilter에는 DataProvider.getDistinctValues()을 사용하여 해당 컬럼의 데이터들을 중복 없이 순차 정렬하여 표시하고 각각의 데이터에 checkbox를 배치합니다.
- checkbox가 클릭되면 check된 데이터들을 하나의 수식으로 조합 후 GridBase.addColumnFilters()함수를 호출하여 Filter로 등록합니다.
- Filter를 등록할 때 hidden 속성이 false이면 다시 Filter Icon을 클랙했을 때 1번의 조건을 만족하지 않아서 Filter 목록이 표시되므로 hidden속성을 true로 등록합니다.
실습
-
전역 변수 선언
GridBase
와DataProvider
객체를 담기 위한 기본 변수와FilterAction
이 선택된 컬럼을 저장하기 위한 filterColumn변수, division을 닫았다가 다시 띠을 때 이미 선택했던 값들을 저장하기 위한 Array autoFilterItems 변수를 전역으로 선언합니다.var gridView; var dataProvider; var filterColumn = null; var autoFilterItems = [];
-
Field및 Column구성, 기초 데이터 구성
dataProvider.setFields([{ fieldName: "textField" }, { fieldName: "numberField", dataType: "number" }]); gridView.setColumns([{ fieldName: "textField", name: "textColumn", width: 200, header: {text: "Text Column"} }, { fieldName: "numberField", name: "numberColumn", width: 200, header: {text: "Number Column"} }]); dataProvider.setRows([{ textField: "A", numberField: 1 }, { textField: "B", numberField: 2 }, { textField: "C", numberField: 3 }, { textField: "D", numberField: 4 }, { textField: "E", numberField: 5 }]);
-
각 컬럼에 “auto filter”
FilterAction
추가var actions = [{ name: "__autofilter", text: "auto filter" }]; gridView.setColumnFilterActions("textColumn", actions); gridView.setColumnFilterActions("numberColumn", actions);
-
onFilterActionClicked 콜백 함수 작성
gridView.onFilterActionClicked = function (grid, column, action, x, y) { if (action == "__autofilter") { filterColumn = gridView.columnByName(column); ... }
filterColumn의 데이터를 spanFilters의 하위에 label과 checkbox형태로 추가
var values = dataProvider.getDistinctValues(filterColumn.fieldName, 100); var span = $("#spanFilters"); span.empty(); values.forEach(function (v) { var label = $("<label />").appendTo(span); var existsFilter = autoFilterItems.indexOf(v+"") >= 0; $("<input />", { type: "checkbox", name: "chkAutoFilterItem", value: v, onclick: "filterCheckChanged();", checked: existsFilter}).appendTo(label); label.append(v); span.append("
"); });divAutoFilter가 표시될 좌표 계산 로직. 이 강좌에서는 페이지가 중앙 정렬되어 margin-left, padding-left값을 구해 absolute position의 좌표값에서 감하는 로직도 구현되었습니다. 실제 사용시에는 이와 다를 수 있으므로 참고하시기 바랍니다.
// 페이지 offset 계산 var page = $("div.page-content > div.wrapper"); var pageOffset = page.offset(); pageOffset.left += parseInt(page.css("padding-left")); // 그리드 offset 계산 및 x,y 결정 var gridOffset = $("#realgrid").offset(); x = x + gridOffset.left - pageOffset.left; y = y + gridOffset.top - pageOffset.top; // divAutoFilter를 컬럼의 우측에 정렬시키기 위해 컬럼의 폭에서 divAutoFilter의 폭를 뺀만큼 x를 증가 width = filterColumn.displayWidth; x += (width - $("#divAutoFilter").outerWidth()); $("#divAutoFilter").css("left", x); $("#divAutoFilter").css("top", y); $("#divAutoFilter").show();
-
checkbox를 변경했을 때 호출되는 filterCheckChanged 함수 선언
function filterCheckChanged(e) { // 기존 auto_result 제거 및 다른 필더 비활성화 var columns = gridView.getColumns(); for(var c in columns) { gridView.removeColumnFilters(columns[c], ["auto_result"]); gridView.activateAllColumnFilters(columns[c], false); } // 선택된 checkbox를 하나의 filter식으로 조합. ex) (value = 'A') or (value = 'B') var filterExpr = ""; var checkedFilters = $("input[name='chkAutoFilterItem']:checked"); autoFilterItems = []; for (var i = 0; i < checkedFilters.length; i++) { autoFilterItems.push(checkedFilters[i].value); if (filterExpr != "") filterExpr += " or "; filterExpr += "(value = '" + checkedFilters[i].value + "')"; }; // auto_result filter 등록 var filters = { name: "auto_result", criteria: filterExpr, active: true, hidden: true }; gridView.addColumnFilters(filterColumn, filters); }
실행화면
각 컬럼의 필터아이콘을 클릭한 후 각 데이터
Text Column은 A, B, C와 같은 형태로 Quotation Mark('
)가 빠진 상태로 입력합니다.
Apply버튼을 누르면 입력한 사용자 지정 필터가 적용됩니다.
전체 소스코드
SCRIPT
<script type="text/javascript" src="/script/realgridjs-lic.js"></script> <script type="text/javascript" src="/script/realgridjs_eval.1.0.14.min.js"></script> <script type="text/javascript" src="/script/realgridjs-api.1.0.14.js"></script> <script language="javascript"> var gridView; var dataProvider; var filterColumn = null; var autoFilterItems = []; $(document).ready( function() { RealGridJS.setTrace(false); RealGridJS.setRootContext("/script"); dataProvider = new RealGridJS.LocalDataProvider(); gridView = new RealGridJS.GridView("realgrid"); gridView.setDataSource(dataProvider); dataProvider.setFields([{ fieldName: "textField" }, { fieldName: "numberField", dataType: "number" }]); gridView.setColumns([{ fieldName: "textField", name: "textColumn", width: 200, header: {text: "Text Column"} }, { fieldName: "numberField", name: "numberColumn", width: 200, header: {text: "Number Column"} }]); dataProvider.setRows([{ textField: "A", numberField: 1 }, { textField: "B", numberField: 2 }, { textField: "C", numberField: 3 }, { textField: "D", numberField: 4 }, { textField: "E", numberField: 5 }]); var actions = [{ name: "__autofilter", text: "auto filter" }]; gridView.setColumnFilterActions("textColumn", actions); gridView.setColumnFilterActions("numberColumn", actions); gridView.onFilterActionClicked = function (grid, column, action, x, y) { if (action == "__autofilter") { filterColumn = gridView.columnByName(column); var values = dataProvider.getDistinctValues(filterColumn.fieldName, 100); var span = $("#spanFilters"); span.empty(); values.forEach(function (v) { var label = $("<label />").appendTo(span); var existsFilter = autoFilterItems.indexOf(v+"") >= 0; $("<input />", { type: "checkbox", name: "chkAutoFilterItem", value: v, onclick: "filterCheckChanged();", checked: existsFilter}).appendTo(label); label.append(v); span.append("<br/>"); }); var page = $("div.page-content > div.wrapper"); var pageOffset = page.offset(); pageOffset.left += parseInt(page.css("padding-left")); var gridOffset = $("#realgrid").offset(); x = x + gridOffset.left - pageOffset.left; y = y + gridOffset.top - pageOffset.top; width = filterColumn.displayWidth; x += (width - $("#divAutoFilter").outerWidth()); $("#divAutoFilter").css("left", x); $("#divAutoFilter").css("top", y); $("#divAutoFilter").show(); } } $("#btnClose").click(function() { $("#divAutoFilter").hide(); }) }) function filterCheckChanged(e) { var columns = gridView.getColumns(); for(var c in columns) { gridView.removeColumnFilters(columns[c], ["auto_result"]); gridView.activateAllColumnFilters(columns[c], false); } var filterExpr = ""; var checkedFilters = $("input[name='chkAutoFilterItem']:checked"); autoFilterItems = []; for (var i = 0; i < checkedFilters.length; i++) { autoFilterItems.push(checkedFilters[i].value); if (filterExpr != "") filterExpr += " or "; filterExpr += "(value = '" + checkedFilters[i].value + "')"; }; var filters = { name: "auto_result", criteria: filterExpr, active: true, hidden: true }; gridView.addColumnFilters(filterColumn, filters); } </script>
HTML
<div id="realgrid" style="width: 100%; height: 350px;"></div> <div id="divAutoFilter" style="display:none; position:absolute; height:200px; background-color:#ffffff; border:1px solid black;"> <span id="spanFilters" style="overflow-y:scroll; display:block; width:100%; height:170px"> </span> <input type="button" id="btnClose" value="Close" /> </div>
관련 데모 페이지
API 참조