일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 탐욕알고리즘
- 코딩테스트
- 그리디알고리즘
- 개발
- 개발자
- codingtest
- ChatGPT
- 파이썬
- SQLD
- javascript
- 프로그래머스
- 백준
- 서버
- jsp
- 알고리즘코딩테스트
- Python
- HTTP상태
- HTTP
- JQuery
- SQLP
- 자바
- 하루코딩
- 챗지피티
- java
- Spring
- 정렬알고리즘
- API
- 네트워크
- SQL
- 알고리즘
- Today
- Total
개발자's Life
[JavaScript] Slick Grid 를 이용하여 Col, Row 고정 시키기 본문
오늘은 회사 신규모듈 예산 기능 개발중에 틀 고정 기능이 있으면 좋을 듯 하여 시간은 빠듯하지만 Slick Grid 의 틀 고정 기능을 사용하여 완성하였습니다.
확실히 컬럼이 많은 테이블일 경우 틀 고정 기능은 필수라 생각이 드네요.
https://github.com/6pac/SlickGrid/blob/master/examples/example-frozen-columns-and-rows.html#L363
GitHub - 6pac/SlickGrid: A lightning fast JavaScript grid/spreadsheet
A lightning fast JavaScript grid/spreadsheet. Contribute to 6pac/SlickGrid development by creating an account on GitHub.
github.com
해당 GitHub 참고 하여 진행 하였고
http://6pac.github.io/SlickGrid/examples/example-frozen-columns-and-rows.html
SlickGrid example: Frozen Columns and Rows
6pac.github.io
데모 페이지 참고하여 완성하였습니다.
<!DOCTYPE HTML>
<html>
<head>
<!-- css 와 스타일도 동일하게 해줘야 합니다. -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="shortcut icon" type="image/ico" href="favicon.ico" />
<title>SlickGrid example: Frozen Columns and Rows</title>
<link rel="stylesheet" href="../slick.grid.css" type="text/css" media="screen" charset="utf-8"/>
<link rel="stylesheet" href="../controls/slick.pager.css" type="text/css" media="screen" charset="utf-8"/>
<link rel="stylesheet" href="../css/smoothness/jquery-ui.css" type="text/css"/>
<link rel="stylesheet" href="examples.css" type="text/css" media="screen" charset="utf-8"/>
<link rel="stylesheet" href="../controls/slick.columnpicker.css" type="text/css" media="screen" charset="utf-8"/>
<style>
.cell-title {
font-weight: bold;
}
.cell-effort-driven {
text-align: center;
}
.cell-selection {
border-right-color: silver;
border-right-style: solid;
background: #f5f5f5;
color: gray;
text-align: right;
font-size: 10px;
}
.slick-row.selected .cell-selection {
background-color: transparent; /* show default selected row background */
}
.slick-headerrow-column {
background: #87ceeb;
text-overflow: clip;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.slick-headerrow-column input {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.slick-row .slick-cell.frozen:last-child,
.slick-header-column.frozen:last-child,
.slick-headerrow-column.frozen:last-child,
.slick-footerrow-column.frozen:last-child {
border-right: 1px solid #999;
}
.slick-row.frozen:last-child .slick-cell {
border-bottom: 1px solid #999;
}
</style>
</head>
<body>
<div style="position:relative">
<div style="width:600px;">
<div class="grid-header" style="width:100%">
<label>SlickGrid</label>
<span style="float:right" class="ui-icon ui-icon-search" title="Toggle search panel"
onclick="toggleFilterRow()"></span>
</div>
<div id="myGrid" style="width:100%;height:350px;"></div>
<div id="pager" style="width:100%;height:20px;"></div>
</div>
<div class="options-panel">
<b>Search:</b>
<hr/>
<div style="padding:6px;">
<label style="width:200px;float:left">Frozen Row:</label>
<input type=text id="frozenRow" style="width:60px;" value="5">
<button id="setFrozenRow">Set</button>
<br/><br/>
<label style="width:200px;float:left">Frozen Column:</label>
<input type=text id="frozenColumn" style="width:60px;" value="2">
<button id="setFrozenColumn">Set</button>
<br/><br/>
<button id="btnSelectRows">Select first 10 rows</button>
<br/>
<h2>Demonstrates:</h2>
<ul>
<li>a filtered Model (DataView) as a data source instead of a simple array</li>
<li>grid reacting to model events (onRowCountChanged, onRowsChanged)</li>
<li>
<b>FAST</b> DataView recalculation and <b>real-time</b> grid updating in response to data changes.<br/>
The grid holds <b>50'000</b> rows, yet you are able to sort, filter, scroll, navigate and edit as if it had 50
rows.
</li>
<li>adding new rows, bidirectional sorting</li>
<li>column options: cannotTriggerInsert</li>
<li>events: onCellChange, onAddNewRow, onKeyDown, onSelectedRowsChanged, onSort</li>
<li><font color=red>NOTE:</font> all filters are immediately applied to new/edited rows</li>
<li>Handling row selection against model changes.</li>
<li>Paging.</li>
<li>inline filter panel</li>
</ul>
</div>
</div>
</div>
<div id="inlineFilterPanelL" style="display:none;background:#dddddd;padding:3px;color:black;">
Show tasks with title including <input type="text" id="txtSearch2">
</div>
<div id="inlineFilterPanelR" style="display:none;background:#dddddd;padding:6px;color:black;">
and % at least
<div style="width:100px;display:inline-block;" id="pcSlider2"></div>
</div>
<!-- 아래 스크립트 경로 지정 -->
<script language="JavaScript" src="../lib/firebugx.js"></script>
<script src="../lib/jquery-3.1.0.js"></script>
<script src="../lib/jquery-ui.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs/Sortable.min.js"></script>
<script src="../slick.core.js"></script>
<script src="../slick.interactions.js"></script>
<script src="../slick.editors.js"></script>
<script src="../slick.formatters.js"></script>
<script src="../plugins/slick.rowselectionmodel.js"></script>
<script src="../slick.grid.js"></script>
<script src="../slick.dataview.js"></script>
<script src="../controls/slick.pager.js"></script>
<script src="../controls/slick.columnpicker.js"></script>
각자 프로젝트 경로에 맞게 플러그인을 해줍니다.
여기서 주의해야할 부분이 전 이전 버전으로 적용해서 사용하다가 틀 고정 기능을 사용하기 위해 있는 스크립트 제외하고
추가해줘야 할 스크립트 셋팅 후 가볍게 실행하였는데 에러 발생해서 보니 옛 스크립트에 없는 기능들이 많이 채워졌더라구요... 이미 사용하시고 계신 분들은 참고해서 진행해주세요!
여기까지는 JSP 셋팅 부분이고
$(function () {
// 이 부분이 기존 입력 Options 으로 지정 해놓은 컬럼 Input 태그에 뿌려줍니다.
$('#frozenColumn').val(options.frozenColumn);
});
function isIEPreVer9() { var v = navigator.appVersion.match(/MSIE ([\d.]+)/i); return (v ? v[1] < 9 : false); }
var dataView;
var grid;
var data = [];
// Grid 에 그려 질 컬럼들 하나하나 셋팅 작업
var columns = [
{
id: "sel",
name: "#",
field: "num",
behavior: "select",
cssClass: "cell-selection",
width: 40,
cannotTriggerInsert: true,
resizable: false,
unselectable: true
},
{
id: "title",
name: "Title",
field: "title",
cssClass: "cell-title",
editor: Slick.Editors.Text,
validator: requiredFieldValidator,
sortable: true
},
{
id: "duration",
name: "Duration",
field: "duration",
editor: Slick.Editors.Text,
sortable: true
},
{
id: "%",
name: "% Complete",
field: "percentComplete",
resizable: false,
width: 80,
formatter: Slick.Formatters.PercentComplete,
editor: Slick.Editors.PercentComplete,
sortable: true
},
{
id: "start",
name: "Start",
field: "start",
editor: Slick.Editors.Date,
sortable: true
},
{
id: "finish",
name: "Finish",
field: "finish",
editor: Slick.Editors.Date,
sortable: true
},
{
id: "effort-driven",
name: "Effort Driven",
cssClass: "cell-effort-driven",
field: "effortDriven",
formatter: Slick.Formatters.Checkmark,
editor: Slick.Editors.Checkbox,
cannotTriggerInsert: true,
sortable: true
},
{
id: "title1",
name: "Title1",
field: "title1",
cssClass: "cell-title",
editor: Slick.Editors.Text,
validator: requiredFieldValidator,
sortable: true
},
{
id: "title2",
name: "Title2",
field: "title2",
cssClass: "cell-title",
editor: Slick.Editors.Text,
validator: requiredFieldValidator,
sortable: true
},
{
id: "title3",
name: "Title3",
field: "title3",
cssClass: "cell-title",
editor: Slick.Editors.Text,
validator: requiredFieldValidator,
sortable: true
},
{
id: "title4",
name: "Title4",
field: "title4",
cssClass: "cell-title",
editor: Slick.Editors.Text,
validator: requiredFieldValidator,
sortable: true
}
];
var columnFilters = {};
// 아래 frozenColumn, frozenRow 에서 설정이 가능하고 -1 로 지정하면
// 틀 고정 없는 순수 Grid 를 그려줍니다.
var options = {
editable: true,
enableAddRow: true,
enableCellNavigation: true,
asyncEditorLoading: true,
forceFitColumns: false,
autoEdit: false,
topPanelHeight: 25,
frozenColumn: 2,
frozenRow: 5,
showHeaderRow: true,
syncColumnCellResize: false
};
var sortcol = "title";
var sortdir = 1;
var percentCompleteThreshold = 0;
var searchString = "";
function requiredFieldValidator(value) {
if (value == null || value == undefined || !value.length) return {
valid: false,
msg: "This is a required field"
};
else
return {
valid: true,
msg: null
};
}
// 틀 고정 Input 값에 값을 넣고 업데이틀 해주면 해당 함수가 실행이 되어 Grid 셋팅이 됩니다.
function updateHeaderRow() {
for (var i = 0; i < columns.length; i++) {
if (columns[i].id !== "selector") {
var header = grid.getHeaderRowColumn(columns[i].id);
$(header).empty();
$("<input type='text'>")
.data("columnId", columns[i].id)
.val(columnFilters[columns[i].id])
.appendTo(header);
}
}
}
function myFilter(item) {
for (var columnId in columnFilters) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
var c = grid.getColumns()[grid.getColumnIndex(columnId)];
if (item[c.field] != columnFilters[columnId]) {
return false;
}
}
}
return true;
}
function percentCompleteSort(a, b) {
return a["percentComplete"] - b["percentComplete"];
}
function comparer(a, b) {
var x = a[sortcol],
y = b[sortcol];
return (x == y ? 0 : (x > y ? 1 : -1));
}
function addItem(newItem, columnDef) {
var item = {
"num": data.length,
"id": "new_" + (Math.round(Math.random() * 10000)),
"title": "New task",
"duration": "1 day",
"percentComplete": 0,
"start": "01/01/2009",
"finish": "01/01/2009",
"effortDriven": false
};
$.extend(item, newItem);
dataView.addItem(item);
}
function toggleFilterRow() {
grid.setTopPanelVisibility(!grid.getOptions().showTopPanel);
}
$(".grid-header .ui-icon").addClass("ui-state-default ui-corner-all").mouseover(function (e) {
$(e.target).addClass("ui-state-hover")
}).mouseout(function (e) {
$(e.target).removeClass("ui-state-hover")
});
$(function () {
// prepare the data
for (var i = 0; i < 50000; i++) {
var d = (data[i] = {});
d["id"] = "id_" + i;
d["num"] = i;
d["title"] = "Task " + i;
d["duration"] = "5 days";
d["percentComplete"] = Math.round(Math.random() * 100);
d["start"] = "01/01/2009";
d["finish"] = "01/05/2009";
d["effortDriven"] = (i % 5 == 0);
d["title1"] = i;
d["title2"] = i;
d["title3"] = i;
d["title4"] = i;
}
dataView = new Slick.Data.DataView();
grid = new Slick.Grid("#myGrid", dataView, columns, options);
grid.setSelectionModel(new Slick.RowSelectionModel());
var pager = new Slick.Controls.Pager(dataView, grid, $("#pager"));
var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);
// move the filter panel defined in a hidden div into an inline secondary grid header row
var $secondaryRow = grid.getTopPanel();
$("#inlineFilterPanelL").appendTo($secondaryRow[0]).show();
$("#inlineFilterPanelR").appendTo($secondaryRow[1]).show();
grid.onCellChange.subscribe(function (e, args) {
dataView.updateItem(args.item.id, args.item);
});
grid.onAddNewRow.subscribe(function (e, args) {
var item = {
"num": data.length,
"id": "new_" + (Math.round(Math.random() * 10000)),
"title": "New task",
"duration": "1 day",
"percentComplete": 0,
"start": "01/01/2009",
"finish": "01/01/2009",
"effortDriven": false
};
$.extend(item, args.item);
dataView.addItem(item);
});
grid.onKeyDown.subscribe(function (e) {
// select all rows on ctrl-a
if (e.which != 65 || !e.ctrlKey) return false;
var rows = [];
for (var i = 0; i < dataView.getLength(); i++) {
rows.push(i);
}
grid.setSelectedRows(rows);
e.preventDefault();
});
grid.onMouseEnter.subscribe(function (e) {
var cell = this.getCellFromEvent(e);
this.setSelectedRows([cell.row]);
e.preventDefault();
});
grid.onMouseLeave.subscribe(function (e) {
this.setSelectedRows([]);
e.preventDefault();
});
grid.onSort.subscribe(function (e, args) {
sortdir = args.sortAsc ? 1 : -1;
sortcol = args.sortCol.field;
if (isIEPreVer9()) {
// using temporary Object.prototype.toString override
// more limited and does lexicographic sort only by default, but can be much faster
var percentCompleteValueFn = function () {
var val = this["percentComplete"];
if (val < 10) {
return "00" + val;
} else if (val < 100) {
return "0" + val;
} else {
return val;
}
};
// use numeric sort of % and lexicographic for everything else
dataView.fastSort((sortcol == "percentComplete") ? percentCompleteValueFn : sortcol, args.sortAsc);
} else {
// using native sort with comparer
// preferred method but can be very slow in IE with huge datasets
dataView.sort(comparer, args.sortAsc);
}
});
// wire up model events to drive the grid
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
dataView.onPagingInfoChanged.subscribe(function (e, pagingInfo) {
var isLastPage = pagingInfo.pageSize * (pagingInfo.pageNum + 1) - 1 >= pagingInfo.totalRows;
var enableAddRow = isLastPage || pagingInfo.pageSize == 0;
var options = grid.getOptions();
if (options.enableAddRow != enableAddRow) grid.setOptions({
enableAddRow: enableAddRow
});
});
$(grid.getHeaderRow()).delegate(":input", "change keyup", function (e) {
columnFilters[$(this).data("columnId")] = $.trim($(this).val());
dataView.refresh();
});
grid.onColumnsReordered.subscribe(function (e, args) {
updateHeaderRow();
});
grid.onColumnsResized.subscribe(function (e, args) {
updateHeaderRow();
});
var h_runfilters = null;
// wire up the slider to apply the filter to the model
// wire up the slider to apply the filter to the model
$("#pcSlider,#pcSlider2").slider({
"range": "min",
"slide": function (event, ui) {
Slick.GlobalEditorLock.cancelCurrentEdit();
if (percentCompleteThreshold != ui.value) {
window.clearTimeout(h_runfilters);
h_runfilters = window.setTimeout(dataView.refresh, 10);
percentCompleteThreshold = ui.value;
}
}
});
// wire up the search textbox to apply the filter to the model
$("#txtSearch,#txtSearch2").keyup(function (e) {
Slick.GlobalEditorLock.cancelCurrentEdit();
// clear on Esc
if (e.which == 27) this.value = "";
searchString = this.value;
dataView.refresh();
});
$("#btnSelectRows").click(function () {
if (!Slick.GlobalEditorLock.commitCurrentEdit()) {
return;
}
var rows = [];
for (var i = 0; i < 10 && i < dataView.getLength(); i++) {
rows.push(i);
}
grid.setSelectedRows(rows);
});
// initialize the model after all the events have been hooked up
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(myFilter);
dataView.endUpdate();
// if you don't want the items that are not visible (due to being filtered out
// or being on a different page) to stay selected, pass 'false' to the second arg
dataView.syncGridSelection(grid, true);
updateHeaderRow();
$("#gridContainer").resizable();
// Row 고정 해주는 버튼.
$('#setFrozenRow').click(function () {
var val = -1;
if ($('#frozenRow').val() != '') {
val = parseInt($('#frozenRow').val());
}
grid.setOptions({
'frozenRow': val
});
updateHeaderRow();
});
// Col 고정 해주는 버튼.
$('#setFrozenColumn').click(function () {
var val = -1;
if ($('#frozenColumn').val() != '') {
val = parseInt($('#frozenColumn').val());
}
grid.setOptions({
'frozenColumn': val
});
updateHeaderRow();
});
})
위 코드에서 주석 달린 부분이 행, 열 고정 시킬때 주의깊게 보셔야 할 부분입니다.
다들 오늘도 수고하셨습니다.
'Front-end' 카테고리의 다른 글
[JavaScript] DataTable 이용하여 간단한 테이블 만들기 (0) | 2023.07.28 |
---|---|
[JavaScript] Slick Grid 와 Select2 박스 사용법 (0) | 2023.05.22 |