[Nexacro N] Grid 트러블슈팅
Nexacro N Grid 개발에서 자주 발생하는 문제(빈 Grid, 콤보 목록 없음, 변경 미전송, 스크롤 스타일 오염 등)의 원인과 해결책, 그리고 trace()를 활용한 디버깅 체크포인트를 정리합니다.
지난 글에서 Grid 렌더링 성능 최적화를 다뤘습니다. Grid 시리즈의 마지막으로, 실무에서 가장 자주 마주치는 Grid 문제들의 원인과 해결책을 정리합니다. 문제가 발생했을 때 이 글을 빠른 참조 가이드로 활용하기 바랍니다.
문제 1: Grid가 텅 비어 보인다
증상: 트랜잭션 후 Dataset에 데이터가 들어왔는데 Grid에 아무것도 표시되지 않는다.
원인:
bindeddataset속성이 Dataset ID와 일치하지 않는다.- Dataset이 Grid와 다른 Form에 선언되어 있고 경로가 맞지 않는다.
- Grid 컴포넌트의
visible = false상태이다.
해결:
function fn_debugEmpty() {
trace("bindeddataset=" + grd.bindeddataset);
trace("ds.rowcount=" + ds.rowcount);
trace("grd.visible=" + grd.visible);
trace("grd.width=" + grd.width + ", height=" + grd.height);
}
trace() 출력으로 연결 상태를 먼저 확인합니다. rowcount가 0이면 트랜잭션 문제이고, 0보다 크면 바인딩이나 가시성 문제입니다.
문제 2: 콤보 셀 드롭다운 목록이 비어 있다
증상: edittype="combo"로 설정한 셀을 클릭해도 드롭다운이 열리지 않거나 빈 목록이 나온다.
원인:
bindingcodedataset이 연결되지 않았다.bindingcodedataset이 연결됐지만 해당 Dataset의 데이터가 아직 로드되지 않았다.codecolumn또는datacolumnID가 Dataset 컬럼명과 다르다.
해결:
function fn_debugCombo() {
var oCol = grd.getColumnById("colDeptCd");
trace("bindingcodedataset=" + oCol.bindingcodedataset);
trace("codecolumn=" + oCol.codecolumn);
trace("datacolumn=" + oCol.datacolumn);
var dsCode = eval(oCol.bindingcodedataset);
trace("코드 Dataset 행수=" + (dsCode ? dsCode.rowcount : "없음"));
}
코드 Dataset이 비어 있다면 공통 코드 로드 트랜잭션이 Grid 렌더링보다 늦게 완료된 것입니다. 코드 로드 콜백 함수 안에서 bindingcodedataset을 재연결합니다.
function fn_loadCodeCb(svcId, errCode, errMsg) {
// 코드 로드 완료 후 바인딩
grd.getColumnById("colDeptCd").bindingcodedataset = "dsDeptCode";
}
문제 3: 편집 후 저장 시 변경 사항이 서버에 전달되지 않는다
증상: Grid에서 값을 수정한 뒤 저장 버튼을 누르면 서버에서 변경 데이터를 받지 못한다.
원인:
- Dataset의
rowType이 여전히NORMAL(1)이다. 즉, 편집이 Dataset에 반영되지 않았다. - 트랜잭션
argvariables에서 Dataset을ds=형식으로만 전달하고 있지 않다.
해결:
function fn_checkRowTypes() {
for (var r = 0; r < ds.rowcount; r++) {
var nType = ds.getRowType(r);
trace("row[" + r + "] rowType=" + nType);
// 1: NORMAL, 2: INSERT, 4: UPDATE, 8: DELETE
}
trace("총 변경 행=" + ds.getUpdatedRowCount());
}
ds.getUpdatedRowCount()가 0이면 Dataset에 변경 플래그가 없는 것입니다. Grid의 edittype="none"인 열은 사용자가 편집해도 Dataset에 반영되지 않습니다. 또한 스크립트에서 직접 ds.setColumn()으로 값을 바꿀 때도 rowType이 UPDATE로 바뀝니다.
문제 4: 스크롤 시 배경색이 엉뚱한 행에 나타난다
증상: 가상화 Grid에서 오류 행 배경색을 setCellBackgroundColor()로 설정했는데, 스크롤 후 다른 행에 색이 표시된다.
원인: 가상화는 DOM을 재사용합니다. setCellBackgroundColor()로 특정 DOM에 색을 칠했는데, 스크롤 후 그 DOM이 다른 행 데이터를 표시하면서 이전 색이 그대로 남습니다.
해결: setCellBackgroundColor() 대신 oncellstyle 이벤트에서 스타일을 지정합니다. 이 이벤트는 DOM이 재사용될 때마다 호출되므로 항상 올바른 스타일이 적용됩니다.
// 가상화 환경에서 올바른 스타일 적용 방법
function grd_oncellstyle(obj, e) {
var sState = ds.getColumn(e.row, "STATE");
if (sState == "ERR") {
e.backgroundColor = "rgba(224,85,85,0.2)";
e.foreColor = "#ff4444";
} else {
e.backgroundColor = ""; // 반드시 초기화
e.foreColor = "";
}
}
else 분기에서 색을 빈 문자열로 초기화하는 것이 핵심입니다. 초기화하지 않으면 이전 DOM의 색이 유지됩니다.
문제 5: addRow + setColumn 후 oncellchange가 발생하지 않는다
증상: 새 행을 추가하고 setColumn()으로 값을 설정했는데 oncellchange 이벤트가 발생하지 않는다.
원인: oncellchange는 Grid에서 사용자 편집에 의해 값이 변경될 때 발생합니다. 스크립트에서 ds.setColumn()을 직접 호출하는 것은 편집이 아니라 프로그램 변경이므로 이벤트가 발생하지 않습니다.
해결: setColumn() 직후 연동 함수를 명시적으로 호출합니다.
function fn_addRow() {
var nRow = ds.addRow();
ds.setColumn(nRow, "QTY", "10");
ds.setColumn(nRow, "PRICE", "5000");
// oncellchange 대신 직접 계산 함수 호출
fn_calcAmt(nRow);
}
문제 6: Grid 행 높이가 의도와 다르게 나온다
증상: rowheight를 설정했는데 특정 행만 높이가 다르게 나온다.
원인: autorowheight="true" 속성이 활성화되어 있거나, 특정 셀의 height 속성이 직접 지정되어 있다.
해결:
// autorowheight 비활성화
grd.set_autorowheight(false);
grd.set_rowheight(24);
// 개별 행 높이 리셋
grd.setRowHeight(-1, 24); // -1은 모든 행에 적용
문제 7: Grid 클릭 후 oncellclick이 발생하지 않는다
증상: Grid 셀을 클릭해도 oncellclick 이벤트 핸들러가 실행되지 않는다.
원인:
- 이벤트 핸들러가 등록되지 않았다(디자인 패널에서 연결 누락).
- 다른 투명 컴포넌트가 Grid 위에 겹쳐 있어 클릭을 가로채고 있다.
- Grid의
enable = false상태이다.
해결:
// 이벤트 동적 연결 확인
trace("oncellclick handler=" + typeof(grd.oncellclick));
trace("grd.enable=" + grd.enable);
// 동적 연결
grd.oncellclick = fn_grdClick;
공통 디버깅 루틴
문제가 발생하면 다음 순서로 점검합니다.
function fn_gridDiagnostic() {
// 1. 기본 상태
trace("=== Grid Diagnostic ===");
trace("grd.name=" + grd.name);
trace("grd.bindeddataset=" + grd.bindeddataset);
trace("grd.enable=" + grd.enable);
trace("grd.visible=" + grd.visible);
// 2. Dataset 상태
trace("ds.rowcount=" + ds.rowcount);
trace("ds.colcount=" + ds.colcount);
trace("ds.updatedRowCount=" + ds.getUpdatedRowCount());
// 3. 현재 포커스
trace("currentrowindex=" + grd.currentrowindex);
trace("currentcolindex=" + grd.currentcolindex);
}
이 진단 함수를 문제 재현 직후에 호출하면 대부분의 원인을 빠르게 파악할 수 있습니다.
지난 글: Grid 렌더링 최적화
다음 글: Dataset 개요 — 데이터의 심장
읽어주셔서 감사합니다. 😊