dkgrid
Version:
A utility class for creating Tabulator grids with JSON configs.
155 lines (141 loc) • 6.08 kB
JavaScript
// dkgrid.js
/**
* DKGridHandler 클래스는 JSON 설정을 기반으로 Tabulator 그리드를 생성하고 관리합니다.
* 이 클래스는 인피니트 스크롤, 페이지네이션, 엑셀 다운로드 등의 기능을 포함합니다.
*/
export class DKGridHandler {
constructor(elementId) {
this.elementId = elementId;
this.table = null;
this.loadedData = {};
// constructor에서는 totalDataCount를 초기화하지 않음.
this.totalDataCount = 0;
}
/**
* JSON 설정 문자열을 받아 그리드를 생성하거나 업데이트합니다.
* @param {string} configJsonText - JSON 형식의 설정 문자열
* @param {number} totalDataCount - 그리드에 표시될 전체 데이터의 수
*/
createGrid(configJsonText, totalDataCount) {
try {
const config = JSON.parse(configJsonText);
const parsedConfig = this._parseFunctionsInConfig(config);
if (this.table) {
this.table.destroy();
this.loadedData = {}; // 그리드 재생성 시 캐시 초기화
}
// 외부에서 받은 totalDataCount로 설정
this.totalDataCount = totalDataCount;
let paginationOption;
if (config.usePaging) {
paginationOption = "remote";
} else {
paginationOption = false;
parsedConfig.height = parsedConfig.height || "400px";
// totalDataCount가 지정되면 paginationSize를 동적으로 설정
parsedConfig.paginationSize = this.totalDataCount;
parsedConfig.pagination = false;
}
this.table = new Tabulator(this.elementId, {
...parsedConfig,
dataTree: true,
dataTreeParentField: "parentId",
pagination: paginationOption,
ajaxRequestFunc: this._loadData.bind(this),
cellEdited: (cell) => {
console.log("셀이 수정되었습니다:", cell.getValue());
}
});
console.log("그리드가 JSON 설정에 따라 성공적으로 생성되었습니다.");
} catch (error) {
console.error("JSON 파싱 또는 그리드 생성 오류:", error);
throw new Error("유효하지 않은 JSON 형식입니다.");
}
}
/**
* 엑셀 파일로 그리드 데이터를 다운로드합니다.
* @param {string} filename - 파일명
*/
downloadExcel(filename = "grid_data.xlsx") {
if (this.table) {
this.table.download("xlsx", filename, { sheetName: "Data" });
} else {
console.warn("그리드가 생성되지 않았습니다.");
}
}
/**
* 가상의 AJAX 데이터 로드 함수 (내부 메소드)
* @private
*/
_loadData(url, params) {
return new Promise((resolve) => {
const page = params.page || 1;
const size = params.size || 50;
this._loadPage(page, size).then(result => {
resolve({
last_page: Math.ceil(this.totalDataCount / size),
data: result.data
});
if (page > 1) this._loadPage(page - 1, size);
if (page < Math.ceil(this.totalDataCount / size)) this._loadPage(page + 1, size);
});
});
}
/**
* 실제 데이터 로딩 로직 (캐싱 포함, 내부 메소드)
* @private
*/
_loadPage(page, size) {
return new Promise(resolve => {
if (this.loadedData[page]) {
console.log(`페이지 ${page} 데이터가 캐시에서 로드되었습니다.`);
resolve(this.loadedData[page]);
return;
}
const start = (page - 1) * size;
const end = Math.min(start + size, this.totalDataCount);
const data = [];
setTimeout(() => {
// 샘플 데이터 생성
for (let i = start; i < end; i++) {
data.push({
id: i + 1,
name: `User ${i + 1}`,
gender: i % 2 === 0 ? "male" : "female",
col: ["red", "blue", "green", "orange"][i % 4],
dob: `${(i % 28) + 1}/${(i % 12) + 1}/${1980 + (i % 20)}`,
parentId: i > 0 && i % 5 === 0 ? Math.floor(Math.random() * i) + 1 : 0,
checkbox: i % 3 === 0
});
}
const result = { data: data };
this.loadedData[page] = result;
console.log(`페이지 ${page} 데이터가 새로 로드되어 캐싱되었습니다.`);
resolve(result);
}, 500);
});
}
/**
* JSON 설정의 함수 문자열을 실제 함수로 변환 (내부 메소드)
* @private
*/
_parseFunctionsInConfig(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
for (const key in obj) {
if (typeof obj[key] === 'string' && obj[key].startsWith('function(')) {
try {
obj[key] = new Function('e', 'cell', obj[key].replace('function(e, cell)', ''));
} catch (e) {
console.error(`Error parsing function string for key "${key}":`, e);
}
} else if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
obj[key] = this._parseFunctionsInConfig(obj[key]);
} else if (Array.isArray(obj[key])) {
obj[key].forEach(item => this._parseFunctionsInConfig(item));
}
}
return obj;
}
}