C20 Tree그리드에서 체크셀렌더러 사용.
들어가며
이번 강좌에서는 상,하위 노드의 check/uncheck에 따라 상,하위 노드의 체크를 조작하는 방법을 배워보도록 하겠습니다.
이론
업무화면을 개발하다보면 트리구조의 메뉴화면이 필요한 경우가 있을 것입니다.
예를들어 상위노드를 체크하는 경우 하위노드를 일괄로 check/uncheck하거나 반대로 하위노드를 check/uncheck하는 경우 그 하위노드의 형제노드(sibling node)의 체크 상태에 따라
부모 노드의 체크 여부를 조작하는 것.
리얼그리드에서는 아래의 두가지 방법을 이용하여 해당 업무를 처리할 수 있습니다.
- 셀 렌더러중 하나인 CheckCellRenderer를 이용하는 방법
- 그리드의 왼쪽에 위치한 CheckBar를 이용하는 방법
이번 강좌에서는 1번인 체크 셀 렌더러를 이용하여 트리그리드의 상,하위 노드를 조작해보도록 하겠습니다.
컬럼과 필드는 아래와 같이 설정합니다.
//필드 배열 객체를 생성합니다.
var fields = [{
    "fieldName": "treeNode"
}, {
    "fieldName": "menuName"
}, {
    "fieldName": "auth"
}];
dataProvider.setFields(fields);
//필드와 연결된 컬럼 배열 객체를 생성합니다.
var columns = [
    "name": "menuName",
    "fieldName": "menuName",
    "width": 350,
    "header": {
        "text": "메뉴명"
    }       
}, {
    "name": "auth",
    "fieldName": "auth",
    "width": 150,
    "header": {
        "text": "권한여부"
    },
    "editable": false,
    "renderer": {
        "type": "check",
        "shape": "box",
        "editable": true,
        "startEditOnClick": true,
        "trueValues": "Y",
        "falseValues": "N"
    },
}];
gridView.setColumns(columns);
treeNode필드는 트리 노드의 구성정보가 들어갈 필드입니다. 화면에 표시되는 필드는 menuName, auth 필드 입니다.
사용할 예제의 데이터는 아래와 같은 형태 입니다.
var data = [ ["0", "\\", "Y"], ["0.001", "영업관리", "Y"], ["0.001.001", "영업관리1-중분류", "Y"], ["0.001.001.001", "영업관리1-소분류1", "Y"], ["0.001.001.002", "영업관리1-소분류2", "Y"], ["0.001.001.003", "영업관리1-소분류3", "Y"], ["0.002", "영업회계", "Y"], ["0.002.001", "영업회계1-중분류", "Y"], ["0.002.001.001", "영업회계1-소분류1", "Y"], ["0.002.001.002", "영업회계1-소분류2", "Y"], ["0.002.002", "영업회계2-중분류", "Y"], ["0.002.002.001", "영업회계2-소분류1", "Y"], ["0.002.002.002", "영업회계2-소분류2", "Y"], ["0.002.002.003", "영업회계2-소분류3", "Y"], ["0.002.002.004", "영업회계2-소분류4", "Y"] ]; dataProvider.setRows(data, "treeNode", true, "", "");
이렇게 표시된 그리드에서 auth(권한여부) 컬럼셀을 클릭하여 값을 변경하는 경우 트리 그리드에서는 onCellEdited() 이벤트가 발생하게 됩니다. 해당 이벤트 안에서 체크된 값에 따라 각 노드를 확인하고 상,하위 노드의 체크를 제어하면 됩니다.
실습에서는 아래 API들을 이용하여 노드정보를 획득하고 체크값들을 제어해보도록 하겠습니다.
부모/자식 ID를 가져오는 API들
- 조상: dataProvider.getAncestors()
- 부모: dataProvider.getParent()
- 자식: dataProvider.getChildren()
- 자손: dataProvider.getDescendants()
실습
- 
    화면에 표시되고 있는 “권한여부” 컬럼의 체크박스를 클릭하여 체크값 변경 후 다른 행의 expander(+/-)를 클릭해보세요. 체크한 행이 현재 편집중이기에 expander가 동작하지 않습니다. 
- 
    체크한 값을 commit()시켜 편집상태를 종료하려면 값이 편집되었을때 발생하는 onCellEdited()안에 아래와 같이 grid.commit()을 추가하여야 합니다. //셀 편집 후 commit() $("#btnSetOnCellEdited").click(function () { gridView.onCellEdited = function (grid, itemIndex, dataRow, field) { grid.commit(true); }; });
- 
    “권한여부” 컬럼의 체크박스를 클릭하여 체크값 변경 후 다른 행의 expander(+/-)를 클릭해보세요. 잘 동작합니다. 
- 
    “auth” 컬럼을 체크하였을때 하위자손 노드들은 현재의 체크값과 같은 값을 set 해주면 됩니다. 상위 노드들은 체크한 형제노드들의 값이 모두 같으면 체크해주고 하나라도 다르면 체크해제를 set 해주면 됩니다. 해당 코드는 아래와 같습니다. //체크셀렌더러 체크 제어 function checkNode(provider, dataRow, checked) { //형제노드체크 후 부모노드 체크 checkSiblingNode(provider, dataRow, checked); //자손노드체크 var desRows = provider.getDescendants(dataRow); for (var i in desRows) { dataProvider.setValue(desRows[i], "auth", checked); } }; function checkSiblingNode(provider, dataRow, checked) { //부모노드 var parent = provider.getParent(dataRow); //형제노드들 var sibling = provider.getChildren(parent); var index = sibling.indexOf(dataRow); //자기자신은 제외 if (index !== -1) sibling.splice(index, 1); if (checked == "Y") { var result = true; for (var i in sibling) { var value = dataProvider.getValue(sibling[i], "auth"); if (checked != value) { result = false; break; } } checked = result ? "Y" : "N"; } else { checked = "N"; } provider.setValue(parent, "auth", checked); if (parent > -1) checkSiblingNode(provider, parent, checked); }
- 
    onCellEdited()안에 위에서 작성한 코드를 추가합니다. $("#btnSetOnCellEdited1").click(function () { //체크셀렌더러 체크 제어 function checkNode(provider, dataRow, checked) { //형제노드체크 후 부모노드 체크 checkSiblingNode(provider, dataRow, checked); //자손노드체크 var desRows = provider.getDescendants(dataRow); for (var i in desRows) { dataProvider.setValue(desRows[i], "auth", checked); } }; function checkSiblingNode(provider, dataRow, checked) { //부모노드 var parent = provider.getParent(dataRow); //형제노드들 var sibling = provider.getChildren(parent); var index = sibling.indexOf(dataRow); //자기자신은 제외 if (index !== -1) sibling.splice(index, 1); if (checked == "Y") { var result = true; for (var i in sibling) { var value = dataProvider.getValue(sibling[i], "auth"); if (checked != value) { result = false; break; } } checked = result ? "Y" : "N"; } else { checked = "N"; } provider.setValue(parent, "auth", checked); if (parent > -1) checkSiblingNode(provider, parent, checked); }; gridView.onCellEdited = function (grid, itemIndex, dataRow, field) { grid.commit(true); var provider = grid.getDataSource(); var fieldName = dataProvider.getOrgFieldName(field); if (fieldName == 'auth') { checkNode(provider, dataRow, grid.getValue(itemIndex, field)); } }; });
실행화면
- 
    화면에 표시되고 있는 “권한여부” 컬럼의 체크박스를 클릭하여 체크값 변경 후 다른 행의 expander(+/-)를 클릭해보세요. 체크한 행이 현재 편집중이기에 expander가 동작하지 않습니다. 
- 
    버튼을 클릭하여 onCellEdited() 안에 commit() 적용하기 
- 
    화면에 표시되고 있는 “권한여부” 컬럼의 체크박스를 클릭하여 체크값 변경 후 다른 행의 expander(+/-)를 클릭해보세요. 잘 동작합니다. 
- 
    CheckNode() 정의하기 
- 
    “권한여부” 컬럼의 체크박스를 클릭하여 체크박스 값이 잘 연동되는지 확인하세요. 
전체 소스코드
SCRIPT
<script type="text/javascript" src="/script/realgridjs-lic.js"></script>
<script type="text/javascript" src="/script/realgridjs_eval.1.1.27.min.js"></script>
<script type="text/javascript" src="/script/realgridjs-api.1.1.27.js"></script>
<script>
var gridView;
var dataProvider;
$(document).ready( function(){
    RealGridJS.setTrace(false);
    RealGridJS.setRootContext("/script");
    
    dataProvider = new RealGridJS.LocalTreeDataProvider();
    gridView = new RealGridJS.TreeView("realgrid");
    gridView.setDataSource(dataProvider);
    //필드 배열 객체를 생성합니다.
    var fields = [{
        "fieldName": "treeNode"
    }, {
        "fieldName": "menuName"
    }, {
        "fieldName": "auth"
    }];
    //DataProvider의 setFields함수로 필드를 입력합니다.
    dataProvider.setFields(fields);
    //필드와 연결된 컬럼 배열 객체를 생성합니다.
    var columns = [{
        "name": "menuName",
        "fieldName": "menuName",
        "width": 350,
        "header": {
            "text": "메뉴명"
        }       
    }, {
        "name": "auth",
        "fieldName": "auth",
        "width": 150,
        "header": {
            "text": "권한여부"
        },
        "editable": false,
        "renderer": {
            "type": "check",
            "shape": "box",
            "editable": true,
            "startEditOnClick": true,
            "trueValues": "Y",
            "falseValues": "N"
        }
    }];
    //컬럼을 GridView에 입력 합니다.
    gridView.setColumns(columns);
    var data = [
      ["0", "\\", "Y"],
      ["0.001", "영업관리", "Y"],
      ["0.001.001", "영업관리1-중분류", "Y"],
      ["0.001.001.001", "영업관리1-소분류1", "Y"],
      ["0.001.001.002", "영업관리1-소분류2", "Y"],
      ["0.001.001.003", "영업관리1-소분류3", "Y"],
      ["0.002", "영업회계", "Y"],
      ["0.002.001", "영업회계1-중분류", "Y"],
      ["0.002.001.001", "영업회계1-소분류1", "Y"],
      ["0.002.001.002", "영업회계1-소분류2", "Y"],
      ["0.002.002", "영업회계2-중분류", "Y"],
      ["0.002.002.001", "영업회계2-소분류1", "Y"],
      ["0.002.002.002", "영업회계2-소분류2", "Y"],
      ["0.002.002.003", "영업회계2-소분류3", "Y"],
      ["0.002.002.004", "영업회계2-소분류4", "Y"]
    ];
    dataProvider.setRows(data, "treeNode", true, "", "");
    gridView.expandAll();   
    //셀 편집 후 commit()
    $("#btnSetOnCellEdited").click(function () {
        gridView.onCellEdited = function (grid, itemIndex, dataRow, field) {
            grid.commit(true);
        }; 
    });
    $("#btnSetOnCellEdited1").click(function () {
        function checkNode(provider, dataRow, checked) {
            //형제노드체크 후 부모노드 체크
            checkSiblingNode(provider, dataRow, checked);
            //자식노드체크
            var desRows = provider.getDescendants(dataRow);
            for (var i in desRows) {
                dataProvider.setValue(desRows[i], "auth", checked);
            }
        };
        function checkSiblingNode(provider, dataRow, checked) {
            //부모노드
            var parent = provider.getParent(dataRow);
            //형제노드
            var sibling = provider.getChildren(parent);
            var index = sibling.indexOf(dataRow);
            //자기자신은 제외
            if (index !== -1) sibling.splice(index, 1);
            if (checked == "Y") {
                var result = true;
                for (var i in sibling) {
                    var value = dataProvider.getValue(sibling[i], "auth");
                    if (checked != value) {
                        result = false;
                        break;
                    }
                }
                checked = result ? "Y" : "N";
            } else {
                checked = "N";
            }
            provider.setValue(parent, "auth", checked);
            if (parent > -1) checkSiblingNode(provider, parent, checked);
        }
        gridView.onCellEdited = function (grid, itemIndex, dataRow, field) {
            grid.commit(true);
            var provider = grid.getDataSource();
            var fieldName = dataProvider.getOrgFieldName(field);
            if (fieldName == 'auth') {
                checkNode(provider, dataRow, grid.getValue(itemIndex, field));
            }
        }; 
    });    
});   
</script>
HTML
<div id="realgrid" style="width: 90%; height: 380px;"></div> <p></p> 1. 화면에 표시되고 있는 "권한여부" 컬럼의 체크박스를 클릭하여 체크값 변경 후 다른 행의 expander(+/-)를 클릭해보세요. 체크한 행이 현재 편집중이기에 expander가 동작하지 않습니다. 2. <button type="button" class="btn btn-primary btn-xs" id="btnSetOnCellEdited">grid.commit()</button> 버튼을 클릭하여 onCellEdited() 안에 commit() 적용하기 3. 화면에 표시되고 있는 "권한여부" 컬럼의 체크박스를 클릭하여 체크값 변경 후 다른 행의 expander(+/-)를 클릭해보세요. 잘 동작합니다. 4. CheckNode() 정의하기 5. <button type="button" class="btn btn-primary btn-xs" id="btnSetOnCellEdited1">onCellEdited() 안에 CheckNode 적용하기</button> 6. "권한여부" 컬럼의 체크박스를 클릭하여 체크박스 값이 잘 연동되는지 확인하세요.
참조
 RealGrid HELP
 RealGrid HELP