Mendix Datagrid2 대신 HTMLSnippet과 JS로 목록 화면 만들기

2026.10.04
  • 시리즈 2/16
  • 개발
  • Mendix 10
  • HTMLSnippet

점검 유형 4종의 목록 화면을 Datagrid2 대신 HTMLSnippet 3개와 JS로 다시 만들었다. 조회는 JSON 한 번으로 받고, 필터와 정렬은 브라우저에서 처리하며, 저장과 삭제는 Microflow를 호출한다.

문제

같은 목록을 점검 유형별로 조금씩 다르게 보여줘야 하고, 상세 검색, 행 펼치기, 편집 팝업, 엑셀 다운로드까지 필요했음

원인

Datagrid2로는 페이지마다 컬럼과 필터를 따로 구성해야 해서, 요청 하나에 페이지 4개를 고쳐야 했음

해결

위젯을 한 벌만 만들고 페이지마다 설정 스니펫만 다르게 둠

구조

Mendix 페이지
① 설정 스니펫페이지마다 다른 값만 담음
② HTML, CSS 스니펫화면 틀과 스타일, 모든 페이지 공통
③ JS 스니펫조회, 필터, 정렬, 팝업, 엑셀, 이벤트 처리
Mendix 런타임
Java Action목록 전체를 JSON 문자열로 반환
Microflow저장, 삭제
DB
페이지 하나에 스니펫 3개, 서버 호출은 Java Action과 Microflow로만
  • ①은 페이지마다 다르고, ②와 ③은 모든 페이지에 같은 내용을 붙임
  • 스니펫 순서는 ① → ② → ③. ③이 실행될 때 ①의 설정값이 있어야 함
  • HTMLSnippet의 Content type은 ①과 ③은 JavaScript, ②는 HTML

설정 스니펫

페이지마다 다른 값만 전역 객체 하나에 담는다. 위젯 코드는 이 값을 읽어서 화면을 그린다.

① 설정 스니펫 (JavaScript)
window.LIST_PAGE_CONFIG = {
  pageType: 'typeA',            // 서버 조회 조건에 쓰는 구분값
  title: '외부 점검',
  columns: ['detectDate', 'site', 'title', 'team', 'dueDate', 'status'],
  canEdit: true
};

목록 조회는 JSON 한 번

Java Action이 목록 전체를 JSON 문자열로 돌려주고, 이를 Microflow로 감싸서 JS에서 호출한다. 화면에 필요한 컬럼만 담는다.

Java Action: JA_GetIssueList_JSON (반환 String)
IContext ctx = Core.createSystemContext();   // 사용자 세션 캐시에 쌓이지 않게
JSONArray arr = new JSONArray();
int batch = 300, offset = 0, max = 10000;

while (offset < max) {
  List<IMendixObject> list = Core.createXPathQuery("//Issue.InspectionIssue")
      .addSort("DetectDate", false)
      .setAmount(batch)
      .setOffset(offset)
      .execute(ctx);
  if (list.isEmpty()) break;

  for (IMendixObject o : list) {
    JSONObject j = new JSONObject();
    j.put("guid", String.valueOf(o.getId().toLong()));
    j.put("title", o.getValue(ctx, "Title"));
    j.put("team", o.getValue(ctx, "Team"));
    // 날짜는 epoch(ms)로 넘기고 화면에서 변환
    Date due = o.getValue(ctx, "DueDate");
    j.put("dueDate", due == null ? JSONObject.NULL : due.getTime());
    Date clear = o.getValue(ctx, "ClearDate");
    j.put("clearDate", clear == null ? JSONObject.NULL : clear.getTime());
    arr.put(j);
  }
  offset += batch;
}
return arr.toString();
시스템 컨텍스트는 권한을 확인하지 않는다createSystemContext로 조회하면 엔티티 접근 규칙이 적용되지 않는다. 사용자별로 보여줄 범위가 다르면 XPath 조건에 직접 넣어야 한다.
③ JS 스니펫: 목록 불러오기
function loadList(onDone) {
  mx.data.action({
    params: { actionname: 'Issue.ACT_GetIssueList_JSON' },
    callback: function (json) {
      var rows = [];
      try { rows = JSON.parse(json || '[]'); } catch (e) { console.error(e); }
      onDone(rows);
    },
    error: function (err) {
      showMessage('목록을 불러오지 못했습니다. 새로고침 후 다시 시도하세요.');
      console.error(err);
    }
  });
}

필터, 정렬, 페이지는 브라우저에서

받은 배열을 상태 객체에 두고, 조건이 바뀔 때마다 걸러서 다시 그린다. 상태 값처럼 계산이 필요한 항목은 받아 온 직후 한 번만 만든다.

③ JS 스니펫: 상태 계산과 필터
var state = { rows: [], keyword: '', status: '', page: 1, size: 20 };

function withStatus(r) {
  var today = new Date().setHours(0, 0, 0, 0);
  if (r.clearDate) r.status = '조치완료';
  else if (r.dueDate && r.dueDate < today) r.status = '지연';
  else r.status = '조치예정';
  return r;
}

function filtered() {
  var kw = state.keyword.toLowerCase();
  return state.rows.filter(function (r) {
    if (state.status && r.status !== state.status) return false;
    return !kw || (r.title || '').toLowerCase().indexOf(kw) > -1;
  });
}

function pageRows(list) {
  var start = (state.page - 1) * state.size;
  return list.slice(start, start + state.size);
}

loadList(function (rows) {
  state.rows = rows.map(withStatus);
  render();   // filtered() → pageRows() 결과로 표를 그림
});

저장과 삭제는 Microflow로

JS에서 객체를 직접 커밋하지 않고 Microflow를 호출한다. 목록 JSON에 담아 둔 guid를 넘긴다.

③ JS 스니펫: 삭제
function removeIssue(guid, onDone) {
  mx.data.action({
    params: {
      actionname: 'Issue.ACT_DeleteIssue',
      applyto: 'selection',
      guids: [guid]
    },
    callback: function () { onDone(); },
    error: function (err) {
      showMessage('삭제하지 못했습니다.');
      console.error(err);
    }
  });
}

관련 글: 4편 Mendix mx.data.commit이 조용히 실패할 때

페이지를 이동하면 JS 스니펫이 다시 실행된다Mendix는 페이지를 이동해도 브라우저 문서를 새로 읽지 않는다. document에 건 이벤트가 이동할 때마다 쌓이므로 정리 코드가 필요하다. 3편에서 다룬다.

이 방식이 맞는 경우

상황Datagrid2 유지JS 위젯 전환
컬럼과 필터단순하고 페이지마다 같음페이지마다 조금씩 다름
상호작용정렬, 검색 정도행 펼치기, 커스텀 팝업, 일괄 처리
데이터 양많음, 서버 페이징 필요수천 건 이하 또는 사전 집계 가능
유지보수Studio Pro만 다룰 수 있음JS를 고칠 사람이 있음

전체를 한 번에 받는 구조라서 데이터가 1만 건을 넘기면서 서버 메모리 문제가 생겼다. 조회 컬럼을 줄이고, 결과를 미리 만들어 두는 방식으로 바꿨다.

관련 글: 5편 Java heap OOM 추적기, 7편 Mendix 첫 접속 지연 줄이기

전환 전 확인할 것

  • 목록 JSON에 이미지나 긴 본문 같은 큰 컬럼을 넣지 않았는가
  • 시스템 컨텍스트로 조회한다면 사용자별 조회 범위를 직접 걸었는가
  • 저장과 삭제를 Microflow로 처리하는가
  • 페이지 이동 시 이벤트를 정리하는 코드가 있는가
  • 예상 데이터 양이 브라우저에서 처리할 수 있는 수준인가
시리즈 목차 16편
  1. PI 담당자가 로우코드로 사내 시스템을 직접 만들고 운영한 기록
  2. Mendix Datagrid2 대신 HTMLSnippet과 JS로 목록 화면 만들기 (현재 글)
  3. Mendix SPA에서 HTMLSnippet JS가 꼬이는 이유: 이벤트 중복과 DOM 공존
  4. Mendix mx.data.commit이 조용히 실패할 때
  5. Mendix Java heap OOM 추적기: base64 이미지 컬럼
  6. Mendix 커밋 롤백, 용량 문제가 아니었다: FileDocument 전환기
  7. Mendix 첫 접속 지연 줄이기: 워밍업과 캐시
  8. Mendix SAML SSO 자동 로그인과 딥링크 유지
  9. Mendix Studio Pro에서 안 바뀌는 스타일 main.scss로 바꾸기
  10. Mendix MPK 파일 열어서 마이크로플로우 구조 보기
  11. SSO 로그 테이블로 MAU와 재방문율 구하는 SQL
  12. Mendix DateTime이 BI 도구에서 하루 빠르게 보이는 이유
  13. 대시보드 숫자가 틀렸을 때 확인하는 순서
  14. 보기 좋은 대시보드에서 할 일을 알려주는 대시보드로
  15. 여러 점검 시스템을 하나로 합치는 데이터 모델
  16. 데이터 비전공자에게 분석 결과 보고하기
  • #Mendix
  • #HTMLSnippet
  • #Datagrid2
  • #JavaScript
  • #JavaAction
  • #로우코드

댓글