B1-3 Column Filtering - Filter 응용 사용자 지정 필터 구현
들어가며
B1-1, B1-2 강좌에서 Filter와 FilterAction의 기본적인 사용방법을 배웠습니다.
이 강좌에서는 Filter
와 FilterAction
을 응용하여 엑셀의 사용자 정의 필터와 유사한 UI로 구현하는 방법을 알아봅시다.
FilterAction에 “사용자 정의 필터” 항목을 추가하여 이 FilterAction을 클릭하였을 때 별도의 Dialog에서 수식을 사용자가 선택하여 Filter로 추가하는 방법으로 강의를 진행하겠습니다.
이론
- GridBase.setColumnFilterActions()함수를 사용하여 각 컬럼에
사용자 정의 필터
라고 표시되는 FilterAction을 추가합니다. FilterAction의 이름은 고유해야하므로 중복되지 않는 하나의 이름을 지정합니다. 이 강좌에서는__customfilter
라고 명명하였습니다. - GridBase.onFilterActionClicked()콜백 함수를 지정하여 Click된 FilterAction이
__customfilter
일 때사용자 자동 필터
Dialog를 표시합니다. - Dialog내의 입력 Control의 이름은 다음과 같습니다.
dialog_condition1 : 첫번째 수식의 비교 조건 dialog_value1 : 첫번째 수식의 비교 값 dialog_condition2 : 두번째 수식의 비교 조건 dialog_value2 : 두번째 수식의 비교 값 dialog_logicOp : 논리 연산
-
비교 조건 dropdown의 내용은 다음과 같습니다.
<option value="value = {text}">=</option> <option value="value <> {text}"><></option> <option value="value > {text}">></option> <option value="value >= {text}">>=</option> <option value="value < {text}"><</option> <option value="value <= {text}"><=</option> <option value="value like '{text}%'">시작 문자</option> <option value="value not like '{text}%'">제외할 시작 문자</option> <option value="value like '%{text}'">끝 문자</option> <option value="value not like '%{text}">제외할 끝 문자</option> <option value="value like '%{text}%'">포함</option> <option value="value not like '%{text}%">포함하지 않음</option>
like
수식은 문자형 컬럼에서만 사용 가능합니다.- 선택된 비교조건과 비교값 논리부호로 Filter에 사용할 수식을 만듭니다.
비교조건 dropdown의 선택값에서 {text}부분을 비교값으로 대체하면 가능합니다.
이 때 like에는 이미 dropdown의 값에 Quotation Mark(
'
)가 포함되어 있지만 like가 아닌 경우 포함되어 있지 않으므로 문자열의 경우 추가해야 합니다. - 다른 컬럼의 필터가 존재하면 결과가 다르게 나올 수 있으므로 GridBase.removeColumnFilters()을 사용하여 기존 custom_filter를 제거하고, GridBase.activateAllColumnFilters()을 사용하여 현재 활성화된 다른 filter들을 비활성화시켜야 합니다. 그 후 GridBase.addColumnFilters() 함수를 호출하여 새로운 custom_filter를 추가합니다. 이 때 추가되는 filter의 active속성을 true로 해서 추가와 동시에 활성화 시킵니다.
실습
-
전역 변수 선언
GridBase와 DataProvider객체를 담기 위한 기본 변수와 FilterAction이 선택된 컬럼을 담기위한 filterColumn변수를 전역으로 선언합니다.
var gridView; var dataProvider; var filterColumn = null;
-
Field및 Column구성, 기초 데이터 구성
dataProvider.setFields([{ fieldName: "textField" }, { fieldName: "numberField", dataType: "number" }]); gridView.setColumns([{ fieldName: "textField", name: "textColumn", width: 200, header: {text: "Text Column"}, filters: [{ name: "A", criteria: "value = 'A'" }, { name: "B", criteria: "value = 'B'" }, { name: "C", criteria: "value = 'C'" }, { name: "D", criteria: "value = 'D'" }, { name: "E", criteria: "value = 'E'" }] }, { fieldName: "numberField", name: "numberColumn", width: 200, header: {text: "Number Column"}, filters: [{ name: "1", criteria: "value = 1" }, { name: "2", criteria: "value = 2" }, { name: "3", criteria: "value = 3" }, { name: "4", criteria: "value = 4" }, { name: "5", criteria: "value = 5" }] }]); dataProvider.setRows([{ textField: "A", numberField: 1 }, { textField: "B", numberField: 2 }, { textField: "C", numberField: 3 }, { textField: "D", numberField: 4 }, { textField: "E", numberField: 5 }]);
-
각 컬럼에 “사용자 정의 필터” FilterAction 추가
var actions = [{ name: "__customfilter", text: "사용자 지정 필터 ..." }]; gridView.setColumnFilterActions("textColumn", actions); gridView.setColumnFilterActions("numberColumn", actions);
-
onFilterActionClicked 콜백 함수 작성
gridView.onFilterActionClicked = function (grid, column, action, x, y) { if (action == "__customfilter") { filterColumn = gridView.columnByName(column); // 다이얼로그에 ColumnHeader.text를 표시 var title = gridView.getColumnProperty(filterColumn, "header"); $("#dialog_columnName").text(title.text); $("#filterDialog").modal('show'); } }
-
Dialog Apply button callback 함수
$("#dialog_btnApply").click(function() { if (filterColumn == null) return; ... });
-
Filter 수식 조합
이 강좌에서는 환경적 요인으로 dropdown의 값 <, >가 자동으로 Encode 되어서 이를 Decode하였으나, 실제 개발 환경에서는 Decode는 하지 않아도 무방합니다.
var expr; var cond1 = $("#dialog_condition1").val().replace("<","<").replace(">", ">"); var val1 = $("#dialog_value1").val(); if (val1 && val1.length > 0) { if (filterColumn.name == "textColumn" && cond1.indexOf("like") < 0) val1 = "'" + val1 + "'"; expr = cond1.replace("{text}", val1); val2 = $("#dialog_value2").val(); if (val2 && val2.length > 0) { if (filterColumn.name == "textColumn" && cond2.indexOf("like") < 0) val2 = "'" + val2 + "'"; var cond2 = $("#dialog_condition2").val().replace("<","<").replace(">", ">"); var expr2 = cond2.replace("{text}", val2); var logicOp = $("input:radio[name='dialog_logicOp']:checked").val(); expr = "(" + expr + ") " + logicOp + " (" + expr2 + ")"; } }
-
Filter 등록
if (expr) { // 모든 컬럼의 기존 custom_filter 제거 및 다른 filter deactivate var columns = gridView.getColumns(); for(var c in columns) { gridView.removeColumnFilters(columns[c], ["custom_filter"]); gridView.activateAllColumnFilters(columns[c], false); } // 새로운 custom filter 추가 var filters = [{ name: "custom_filter", criteria: expr, active: 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; $(document).ready( function() { $("#dialog_btnApply").click(function() { if (filterColumn == null) return; var expr; var cond1 = $("#dialog_condition1").val().replace("<","<").replace(">", ">"); var val1 = $("#dialog_value1").val(); if (val1 && val1.length > 0) { if (filterColumn.name == "textColumn" && cond1.indexOf("like") < 0) val1 = "'" + val1 + "'"; expr = cond1.replace("{text}", val1); val2 = $("#dialog_value2").val(); if (val2 && val2.length > 0) { if (filterColumn.name == "textColumn" && cond2.indexOf("like") < 0) val2 = "'" + val2 + "'"; var cond2 = $("#dialog_condition2").val().replace("<","<").replace(">", ">"); var expr2 = cond2.replace("{text}", val2); var logicOp = $("input:radio[name='dialog_logicOp']:checked").val(); expr = "(" + expr + ") " + logicOp + " (" + expr2 + ")"; } } if (expr) { // 모든 컬럼의 기존 custom_filter 제거 및 다른 filter deactivate var columns = gridView.getColumns(); for(var c in columns) { gridView.removeColumnFilters(columns[c], ["custom_filter"]); gridView.activateAllColumnFilters(columns[c], false); } // 새로운 custom filter 추가 var filters = [{ name: "custom_filter", criteria: expr, active: true }]; gridView.addColumnFilters(filterColumn, filters); } $("#filterDialog").modal('hide'); filterColumn = null; }); 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"}, filters: [{ name: "A", criteria: "value = 'A'" }, { name: "B", criteria: "value = 'B'" }, { name: "C", criteria: "value = 'C'" }, { name: "D", criteria: "value = 'D'" }, { name: "E", criteria: "value = 'E'" }] }, { fieldName: "numberField", name: "numberColumn", width: 200, header: {text: "Number Column"}, filters: [{ name: "1", criteria: "value = 1" }, { name: "2", criteria: "value = 2" }, { name: "3", criteria: "value = 3" }, { name: "4", criteria: "value = 4" }, { name: "5", criteria: "value = 5" }] }]); 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: "__customfilter", text: "사용자 지정 필터 ..." }]; gridView.setColumnFilterActions("textColumn", actions); gridView.setColumnFilterActions("numberColumn", actions); gridView.onFilterActionClicked = function (grid, column, action, x, y) { if (action == "__customfilter") { filterColumn = gridView.columnByName(column); var title = gridView.getColumnProperty(filterColumn, "header"); $("#dialog_columnName").text(title.text); $("#filterDialog").modal('show'); } } }) </script>
HTML
<div id="realgrid" style="width: 100%; height: 200px;"></div> <div class="modal fade" id="filterDialog" role="dialog"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> <h4 class="modal-title">사용자 지정 자동 필터</h4> </div><div class="modal-body"> <label>찾을 조건:</label> <div style="margin-left: 10px"> <label id="dialog_columnName">Column</label> <div style="margin-left: 10px"> <form class="form-inline"> <select id="dialog_condition1" class="form-control" /> <option value="value = {text}">=</option> <option value="value <> {text}"><></option> <option value="value > {text}">></option> <option value="value >= {text}">>=</option> <option value="value < {text}"><</option> <option value="value <= {text}"><=</option> <option value="value like '{text}%'">시작 문자</option> <option value="value not like '{text}%'">제외할 시작 문자</option> <option value="value like '%{text}'">끝 문자</option> <option value="value not like '%{text}">제외할 끝 문자</option> <option value="value like '%{text}%'">포함</option> <option value="value not like '%{text}%">포함하지 않음</option> </select> <input type="text" id="dialog_value1" class="form-control" /> </form> <form class="form-inline"> <div class="radio"> <label> <input type="radio" name="dialog_logicOp" id="dialog_logicAnd" value="and"> 그리고 </label> </div><div class="radio"> <label> <input type="radio" name="dialog_logicOp" id="dialog_logicOr" value="or"> 또는 </label> </div></form> <form class="form-inline"> <select id="dialog_condition2" class="form-control"/> <option value="value = {text}">=</option> <option value="value <> {text}"><></option> <option value="value > {text}">></option> <option value="value >= {text}">>=</option> <option value="value < {text}"><</option> <option value="value <= {text}"><=</option> <option value="value like '{text}%'">시작 문자</option> <option value="value not like '{text}%'">제외할 시작 문자</option> <option value="value like '%{text}'">끝 문자</option> <option value="value not like '%{text}">제외할 끝 문자</option> <option value="value like '%{text}%'">포함</option> <option value="value not like '%{text}%">포함하지 않음</option> </select> <input type="text" id="dialog_value2" class="form-control" /> </form> </div></div></div><div class="modal-footer"> <button type="button" class="btn btn-primary" id="dialog_btnApply">Apply</button> <button type="button" class="btn btn-default" id="dialog_btnClose" data-dismiss="modal">Close</button> </div></div></div> </div>
관련 데모 페이지
API 참조