ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Toast grid 함수 및 이벤트 예시
    DEV/javascript 2022. 2. 17. 15:56

    Toast grid를 사용하면서 가장 많이 쓴 이벤트와 함수를 남겨 두려고 한다.

     

    https://nhn.github.io/tui.grid/latest/Grid

     

    https://nhn.github.io/tui.grid/latest/Grid/

    Occurs when the grid data is updated and the grid is rendered onto the DOM The event occurs only in the following API as below. 'resetData', 'restore', 'reloadData', 'readData', 'setPerPage' with 'dataSource', using 'dataSource' PROPERTIES

    nhn.github.io

     

    공식 페이지에 아주 깔끔하게 나열 되어 있으니 참고하자.

     

    클릭 이벤트, 업데이트 이벤트, 클릭한 Row 색상 변경, 클릭한 Row 데이터 가져오기, 그리드 스크롤 최상단 이동(이건 사실 지원하는 함수는 아니지만... 아무튼) 정도로 충분하였다.

     

    아래 코드를 참조하자.

     

    // 그리드 생성
    const GridObject  = tui.Grid;
    GridObject = new Grid({
    	...
    )}
    
    // 그리드에 data 삽입
    GridObject.resetData(data)
    
    // 그리드 업데이트 이벤트 (그리드가 업데이트 됐을 때)
    GridObject.on('onGridUpdated', (ev) => {
    	// 그리드 레이아웃 새로고침 (로드가 다 되지 않는 경우 그리드가 흰색 화면으로 출력될 때가 있다.)
        GridObject.refreshLayout();
    });
    
    // 그리드 클릭 이벤트
    GridObject.on('click', ev => {
    	// 클릭한 Row의 정보를 dataRow에 저장
        let dataRow = GridObject.getRow(ev.rowKey);
    	
    	// 클릭한 Row의 색을 변경 (강조 효과, 클릭 했다는 효과를 줄 때)
    	GridObject.addSelectionOnly(ev.rowKey);
    	
    	// 클릭한 컬럼 이름이 "..." 인 경우
    	if(ev.columnName == "_checked"){
    		...
    	}
    	
    	// 그리드 내용 초기화(Clear)
    	GridObject.dataClear();
    });	
    
    // 현재 클릭하여 Focus된 Row(Cell) 정보를 가져온다.
    const focusCell = GridObject.getFocusedCell()
    
    // 그리드 스크롤을 최상단으로 이동
    // Grid 객체를 생성한 div(또는 담은 요소) id값을 지정하여 사용 가능하다.
    $('html, body').animate({
    	scrollTop : $('#gridDivId .tui-grid-body-area').scrollTop(0)
    } , 500);

     

    * 추가!

    하단 js/css를 추가해야 개별 함수 사용이 가능하다.


    * 추가 JS

    /**
     * TOAST UI Grid Settings
     * 토스트 그리드 기본 UI설정(색상 및 굵기 등의 스타일 설정)
     */
     const GridSettings = {
        language: {
            localeCode: "ko",                           // localeCode : 언어 설정 (en, ko)
            data: {
                display: { 
                    noData: "검색 결과가 없습니다.",      // noData : 빈 값일 때 표시하는 형식
                },
            }
        },
        theme: {
            presetName: "clean",                        // presetName : 기본 테마 설정 (default, striped, clean)
    
            extOptions: {                               // <<커스텀 옵션설정>>
                outline: {                              // [ outline ] : 그리드 바깥 선 설정
    	            border: '#bbbbbb',                  //  border : 색깔
    	            showVerticalBorder: true,           //  showVerticalBorder : 바깥 세로 선 여부(boolean)
    	        },
    	        selection: {                            // [ selection ] : 행, 열의 헤더를 선택하면 해당 부분이 선택되며 나오는 색상 설정
    	         //   background: '#f5d1ba',              //  background : 바탕색
                 background : '#1eed11',
    	            border: '#bbbbbb',                  //  border : 선 색
    	        },
    	        scrollbar: {                            // [ scrollbar ] : 스크롤바
    	            border: 'rgb(205,205,205)',         //  border : 선 색
    	            background: 'rgb(248,248,248)',     //  background : 바탕 색
    	            emptySpace: 'rgb(240,240,240)',     //  emptySpace : 스크롤 빈 부분 색상
    	            thumb: 'rgb(205,205,205)',          //  thumb : 스크롤 부분 색상
                    active: 'rgb(70,70,70)'             //  active : 마우스오버, 클릭할 때 색깔
    	        },
    	        frozenBorder: {                         // [ frozenBorder ] : 고정 컬럼 
    	            border: 'rgb(233,233,233)',         //  border : 선 색 
    	        },
    	        area: {                                 // [area] : 검색 후 표시된 열을 제외한 부분 ( 표의 높이 - 열의 높이 = area )
    	            header: {                           
    	                background: 'rgb(233, 233, 233)', //  header : 컬럼이 없는 헤더의 색상을 나타낸다.
    	                border: '#bbbbbb',                //  **border : [ cell ] - header 와 맞추는 것이 좋다. 현재는 오버되어 색상이 표기된다.
    	            },
    	            body: {                             //  body : 빈 열 값의 부분 색상
                        background: '#ffffff',              
                    },
    	        },
    	        row: {                                  // [ row ] : 열
    	            hover: {                            // hover : 마우스 오버시
    	                background: '#e9f8e8',
    	            },
    	            dummy: {                            // dummy : 비활성 시
    	                background: '#f5d1ba',
    	            },
    	        },
    	        cell: {                             // [ cell ] : 각 셀의 색상 지정
    	            normal: {
    	                border: '#bbbbbb',
    	                text: 'black',
    	                showVerticalBorder: true,
    	                showHorizontalBorder: true,
    	            },
    	            header: {                       //  header : 상단 제목 열
    	                background: 'rgb(233, 233, 233)',
    	                border: '#bbbbbb',
    	                text: 'black',
    	                showVerticalBorder: true,
    	                showHorizontalBorder: true,
    	            },
    	            selectedHeader: {               //  selectedHeader : 선택한 제목 색상
    	                background: 'rgb(233, 233, 233)',
    	            },
    	            rowHeader: {                    //  rowHeader : 좌측 제목 행
    	                background: 'rgb(233, 233, 233)',
    	                border: '#bbbbbb',
    	                text: 'black',
    	                showVerticalBorder: true,
    	                showHorizontalBorder: true,
    	            },
    	            selectedRowHeader: {            //  selectedRowHeader : 선택한 열 색상
    	                background: 'rgb(233, 233, 233)',
    	            },
    	            focused: {                      //  focused : 선택한 셀 색상 
    	                background: "#f5d1ba",
                        border: "#bbbbbb",
                    },
                    focusedInactive: {              //  focusedInactive : 선택 후 표 바깥을 선택하면 나타나는 색상
                        border: "#bbbbbb"
                    },
                    summary: {                      //  summary : 요약 열에 사용할 색상
                        background: '#f1f5ff',
                        border: '#bbbbbb',
                        text: 'black',
                        showVerticalBorder: true,
                        showHorizontalBorder: true,
                    },
    	        },
    	    },
        },
        defaultOptions: {                           // << options >>
            header: {                               // [ header ] : 헤더의 속성 설정
                height: 28,                         // height : 기본 높이 설정(px;num)
                align: 'center',                    // align : 가로정렬 ('left', 'center', 'right')
                valign: 'middle',                   // valign : 세로정렬 ('top', 'middle', 'bottom')
            },
            minRowHeight: 25,                       // rowHeight : 열의 최소높이(px)    ==> **25px이하로 설정하게 되면 스타일이 틀어지기 때문에 낮은 숫자로 변경되는 것을 권장하지 않습니다.
            rowHeight: 25,                          // rowHeight : 열의 높이(px)        ==> **25px이하로 설정하게 되면 스타일이 틀어지기 때문에 낮은 숫자로 변경되는 것을 권장하지 않습니다.
            minBodyHeight: 50,                      // minBodyHeight : 표의 최소 크기
            bodyHeight: 300,                        // bodyHeight : 표의 크기
            width: "auto",                          // width : 너비
            heightResizable: false,                 // heightResizable : 높이 마우스 조절
            usageStatistics: false,                 // usageStatistics : hostname전송 여부 설정
            scrollX: true,                          // scrollX : 가로 축 이동 추가 여부(boolean)
            scrollY: true,                          // scrollY : 세로 축 이동 추가 여부(boolean)
            copyOptions: {                          // [ copyOptions ] : 복사할 때 사용할 값 지정
                useFormattedValue: true,            //  useFormattedValue : 포멧된 값을 복사 혹은 원본 데이터 복사
            },
            columnOptions: {                        // [ columnOptions ]
                minWidth: 50,                       //  minWidth : 최소 너비 사이즈
                resizable: true,                    //  resizable : 컬럼의 고정 폭을 조정 여부(boolean).
                frozenCount: 0,                     //  frozenCount : 고정 컬럼의 개수
                frozenBorderWidth: 1,               //  frozenBorderWidth : 고정 컬럼의 경계선 너비(px)
            },
        },
    }
    
    
    /**
     * Customizing TOAST UI Grid
     * https://nhn.github.io/tui.grid/latest/Grid
     */
     class Grid extends tui.Grid {
        #selectedRowKey;
        constructor(props) {
            const options = { ...GridSettings.defaultOptions, ...props };
            super(options);
            this.#selectedRowKey = -1;
        }
        getSelectedRowKey() {
            return this.#selectedRowKey;
        }
        /**
        * unSelection
        */
        unSelection(grid) {
            for ( var i = 0 ; i < grid.getRowCount() ; i++ ) {
                this.removeRowClassName(i, "cell-selection");
            }
            //this.removeRowClassName(this.#selectedRowKey, "cell-selection");
        }
        /**
        * Add style when selecting row
        * @param {object} ev 
        */
        addSelectionOnly( rowKey ) {      
            if (typeof rowKey != "number") return;
            this.removeRowClassName(this.#selectedRowKey, "cell-selection");
            this.addRowClassName(rowKey, "cell-selection");
            this.#selectedRowKey = rowKey;
        }
        /**
        * Add style when selecting row
        * @param {object} ev 
        */
        addSelection(ev = {}) {
            if (typeof ev.rowKey != "number") return;
            let rowData = this.getRow(ev.rowKey);
            let checked = rowData._attributes.checked;
            if (checked)    this.removeRowClassName(ev.rowKey, "cell-selection");
            else            this.addRowClassName(ev.rowKey, "cell-selection");
            this.#selectedRowKey = ev.rowKey;
        }
        /**
         * Sort by clicking column header
         * @param {object} ev 
         */
        clickSort(ev = {}) {
            if (ev.targetType != "columnHeader") return;
            // this.removeRowClassName(this.#selectedRowKey, "cell-selection");
            if (!ev.nativeEvent.target.className.includes("tui-grid-cell-header")) return;
            let sortingBtn = ev.nativeEvent.target.children[0];
            if (!sortingBtn || !sortingBtn.className.includes("tui-grid-btn-sorting")) return;
            sortingBtn.click();
        }
        /**
         * Check by clicking row
         * @param {object} ev 
         * @param {object} grid 
         * @param {boolean} onlyOne 
         */
        clickCheck(ev = {}, grid, onlyOne = false) {
             console.log(ev)
            if (typeof ev.rowKey != "number" && ev.columnName == "_checked" ) {
                let gridCount = grid.getRowCount();
                let isCheckAll = gridCount == grid.getCheckedRows().length ? true : false ;
                if ( isCheckAll ) {
                    for ( var i = 0 ; i < gridCount ; i++ ) {
                        this.removeRowClassName(i, "cell-selection");
                    }
                } else {
                    for ( var i = 0 ; i < gridCount ; i++ ) {
                        this.addRowClassName(i, "cell-selection");
                    }
                } 
            } else if (typeof ev.rowKey != "number") {
                return;
            } else {
                console.log(ev)
                let rowData = this.getRow(ev.rowKey);
                let checked = rowData._attributes.checked;
                if (onlyOne) this.uncheckAll();
                if (checked) this.uncheck(ev.rowKey);
                else this.check(ev.rowKey)
            }
        }
    
    
        /**
         * Check by clicking row
         * @param {object} ev 
         * @param {object} grid 
         * @param {boolean} onlyOne 
         */
        checkboxCheck( grid, rowKey) {
            
            let rowData = grid.getRow(rowKey);
            let checked = rowData._attributes.checked;
            if (!checked) this.check(rowKey);
        }
    
        /**
         * Check by clicking row
         * @param {object} ev 
         * @param {object} grid 
         */
         clickAllAddSelection(ev = {}, grid) {
             if (typeof ev.rowKey != "number" && ev.columnName == "_checked" ) {
                let gridCount = grid.getRowCount();
                let isCheckAll = gridCount == grid.getCheckedRows().length ? true : false ;
                if ( isCheckAll ) {
                    for ( var i = 0 ; i < gridCount ; i++ ) {
                        this.removeRowClassName(i, "cell-selection");
                    }
                } else {
                    for ( var i = 0 ; i < gridCount ; i++ ) {
                        this.addRowClassName(i, "cell-selection");
                    }
                } 
            }
            return;
        }
    
        /**
         * @param {number} rowCount 
         */
        resetDummyData(rowCount = 0) {
            const rows = [];
            const columns = this.getColumns();
            for (let i = 0; i < rowCount; i++) {
                const row = {};
                columns.forEach(col => {
                    row[col.name] = (Math.random() * 10000000000).toFixed();
                });
                rows.push(row);
            }
            this.resetData(rows);
        }
        /**
         * @param {string} fileName 
         */
        exportExcel(fileName) {
            fileName = `${fileName || "excel"}.xls`;
            const gridData = this.getData();
            const gridColumns = this.getColumns();
            let tableStr = "";
    
            //헤더
            tableStr += "<thead><tr>";
            for (let col of gridColumns) {
                if (col["hidden"] == false) {
                    tableStr += `<th>${col["header"]}</th>`;
                }
            }
            tableStr += "</tr></thead>";
    
            //내용
            tableStr += "<tbody>";
            for (let gridRow of gridData) {
                tableStr += "<tr>";
                for (let col of gridColumns) {
                    if (col["hidden"] == false) {
                        tableStr += `<td style="mso-number-format:'\@'">${gridRow[col["name"]]}</td>`;
                    }
                }
                tableStr += "</tr>";
            }
            tableStr += "</tbody>";
    
            const tableEl = $("<table></table>").html(tableStr);
            tableEl.find('input').each((index, elem) => $(elem).remove());
    
            tableToExcel(tableEl, fileName);
        }
        /**
         * Get number of rows per page
         * @return {number} perPage
         */
        getPaginationPerPage() {
            const pagenation = this.getPagination();
            if (pagenation && pagenation._options) {
                return pagenation._options.itemsPerPage;
            } else {
                return null;
            }
        }
        /**
         * Returns the left position of the scrollbar.
         * @returns {number} scrollLeft
         */
        getScrollLeft() {
            return this.store.viewport.scrollLeft;
        }
    
        /**
         * Return the object that contains all values in the specified row.
         * @returns {Object}  The object that contains all values in the row.
         */
        getSelection() {
            return this.getRow(this.#selectedRowKey);
        }
    
        /**
         * 
         * @returns {Object}  The object that contains all values in the row.
         */
        getRowKey(grid, value) {
    
            let exist = grid.getData().filter(function(e){ 
                return e[Object.keys(value)] == value[Object.keys(value)] ;
            });
    
            if(exist.length == 1){
                return exist[0].rowKey;
            }else{
                return null; 
            }
        }
    
        /**
         * Set the left position of the scrollbar.
         * @param {number} scrollLeft 
         */
        setScrollLeft(scrollLeft) {
            this.store.viewport.scrollLeft = scrollLeft;
        }
        /**
         * Set the current page
         * @param {number} page 
         */
        setPage(page) {
            this.resetData(this.getData(), { 
                pageState: { page } 
            });
        }
    
        dataClear(){
            this.#selectedRowKey = -1;
            this.resetData([]);
        }
    }
    
    
    
    /**
     * https://nhn.github.io/tui.grid/latest/Grid#applyTheme
     */
    Grid.applyTheme(GridSettings.theme.presetName, GridSettings.theme.extOptions); 
    
    /**
     * https://nhn.github.io/tui.grid/latest/Grid#setLanguage
     */
    Grid.setLanguage(GridSettings.language.localeCode, GridSettings.language.data);

    * 추가 CSS

    /* TOAST Grid */
    .tui-grid-layer-state {
        /* outline border */
        border-left: 1px solid rgb(205, 205, 205) !important;
    }
    
    /* SELECTED ROW */
    .tui-grid-cell.cell-selection {
        background-color: rgba(116, 185, 255, .1) !important;
    }
    
    /* HOVER ROW */
    .tui-grid-row-hover>.tui-grid-cell {
        background-color: rgba(116, 185, 255, .1) !important;
    }
    
    /* DRAG ROW DELETE */
    .tui-grid-layer-selection {
        display: none;
    }
    
    .tui-grid-scrollbar-left-bottom {
        border-width: 0 0;
        border-left-width: 1px;
    }
    
    .tui-grid-cell-has-input .tui-grid-cell-content {
        padding-top: 0px;
        padding-bottom: 0px;
    }
    
    .tui-grid-row-header-checkbox {
        padding: 0;
    }
    
    .tui-grid-layer-focus-deactive {
        display: none !important;
    }
    
    .tui-grid-layer-focus-border {
        display: none !important;
    }

    Toast Grid 예시

    https://seokbong.tistory.com/14

     

    Javascript Toast grid 예시

    이번 프로젝트에서 Toast Grid를 사용했다. https://ui.toast.com/tui-grid TOAST UI :: Make Your Web Delicious! The TOAST UI Is Free Open-source JavaScript UI Libraries Maintained By NHN. ui.toast.com..

    seokbong.tistory.com

     

    댓글

Designed by Tistory.