Translate

[jqGrid] addJSONData 메소드 설명







환경: jqGrid v4.7.1 이하 (무료버전)



json 데이터를 일괄적으로 업데이트하는 addJSONData 메소드는 공식문서에도 나와있어 종종 사용할텐데 모르고 사용하면 디버깅을 하느라 시간을 버리게된다.


https://github.com/tonytomov/jqGrid/blob/v4.7.1/js/jquery.jqGrid.js#L1505
1004lucifer
/**
 * addJSONData
 * @param data colModel 형식의 json object 또는 jsonReader 형식의 json object
 * @param t jqGrid
 * @param rcnt 일반적으로 1
 * @param more true인 경우 페이지를 업데이트 하지 않는다.
 * @param adjust 동적스크롤그리드인 경우 npage 숫자 값 - 일반적으로 0
 */
addJSONData = function (data, t, rcnt, more, adjust) {
  var startReq = new Date();
  if (data) {
    // 트리그리드, 동적스크롤그리드가 아닌경우
    if (ts.p.treeANode === -1 && !ts.p.scroll) {
      // 그리드에서 1번째 빈row를 남기고 모두 삭제
      emptyRows.call(ts, false, true);
      rcnt = 1;
    } else { rcnt = rcnt > 1 ? rcnt : 1; }
  } else { return; }

  var dReader, locid = "_id_", frd,
    locdata = (ts.p.datatype !== "local" && ts.p.loadonce) || ts.p.datatype === "jsonstring";
  if (locdata) { ts.p.data = []; ts.p._index = {}; ts.p.localReader.id = locid; }
  ts.p.reccount = 0;
  if (ts.p.datatype === "local") {
    dReader = ts.p.localReader;
    frd = 'local';
  } else {
    dReader = ts.p.jsonReader;
    frd = 'json';
  }
  var self = $(ts), ir = 0, v, i, j, f = [], cur, gi = ts.p.multiselect ? 1 : 0, si = ts.p.subGrid === true ? 1 : 0, addSubGridCell, ni = ts.p.rownumbers === true ? 1 : 0, arrayReader = orderedCols(gi + si + ni), objectReader = reader(frd), rowReader, len, drows, idn, rd = {}, fpos, idr, rowData = [], cn = (ts.p.altRows === true) ? ts.p.altclass : "", cn1;
  ts.p.page = intNum($.jgrid.getAccessor(data, dReader.page), ts.p.page);
  ts.p.lastpage = intNum($.jgrid.getAccessor(data, dReader.total), 1);
  ts.p.records = intNum($.jgrid.getAccessor(data, dReader.records));
  ts.p.userData = $.jgrid.getAccessor(data, dReader.userdata) || {};
  
  // 서브그리드 사용하는경우
  if (si) {
    addSubGridCell = $.jgrid.getMethod("addSubGridCell");
  }
  
  if (ts.p.keyName === false) {
    // keyName 옵션을 사용하지 않으면 Reader의 id가 index로 사용(기본값: id)
    idn = $.isFunction(dReader.id) ? dReader.id.call(ts, data) : dReader.id;
  } else {
    idn = ts.p.keyName;
  }

  // data객체에서 row 추출
  drows = $.jgrid.getAccessor(data, dReader.root); // jsonReader 형식인 경우
  if (drows == null && $.isArray(data)) { drows = data; } // colModel 형식인 경우
  if (!drows) { drows = []; }

  // 데이터가 1개이상 있으면서 page 번호가 0보다 작으면 강제로 page를 1로 셋팅
  len = drows.length; i = 0;
  if (len > 0 && ts.p.page <= 0) { ts.p.page = 1; }

  var rn = parseInt(ts.p.rowNum, 10), br = ts.p.scroll ? $.jgrid.randId() : 1, altr, selected = false, selr;
  if (adjust) { rn *= adjust + 1; }
  
  // deselectAfterSort 옵션 - 소팅을 적용시키면 선택된 row가 선택해제 됨 (기본값: true)
  if (ts.p.datatype === "local" && !ts.p.deselectAfterSort) {
    selected = true;
  }
  var afterInsRow = $.isFunction(ts.p.afterInsertRow), grpdata = [], hiderow = false, groupingPrepare;

  // 데이터 그룹화 사용하는경우
  if (ts.p.grouping) {
    hiderow = ts.p.groupingView.groupCollapse === true;
    groupingPrepare = $.jgrid.getMethod("groupingPrepare");
  }
  while (i < len) {
    cur = drows[i];
    idr = $.jgrid.getAccessor(cur, idn);
    if (idr === undefined) {
      if (typeof idn === "number" && ts.p.colModel[idn + gi + si + ni] != null) {
        // reread id by name
        idr = $.jgrid.getAccessor(cur, ts.p.colModel[idn + gi + si + ni].name);
      }
      if (idr === undefined) {
        idr = br + i;
        if (f.length === 0) {
          if (dReader.cell) {
            var ccur = $.jgrid.getAccessor(cur, dReader.cell) || cur;
            idr = ccur != null && ccur[idn] !== undefined ? ccur[idn] : idr;
            ccur = null;
          }
        }
      }
    }
    idr = ts.p.idPrefix + idr;
    altr = rcnt === 1 ? 0 : rcnt;
    cn1 = (altr + i) % 2 === 1 ? cn : '';
    if (selected) {
      if (ts.p.multiselect) {
        selr = ($.inArray(idr, ts.p.selarrrow) !== -1);
      } else {
        selr = (idr === ts.p.selrow);
      }
    }
    var iStartTrTag = rowData.length;
    rowData.push("");
    if (ni) {
      rowData.push(addRowNum(0, i, ts.p.page, ts.p.rowNum));
    }
    if (gi) {
      rowData.push(addMulti(idr, ni, i, selr));
    }
    if (si) {
      rowData.push(addSubGridCell.call(self, gi + ni, i + rcnt));
    }
    rowReader = objectReader;
    if (dReader.repeatitems) {
      if (dReader.cell) { cur = $.jgrid.getAccessor(cur, dReader.cell) || cur; }
      if ($.isArray(cur)) { rowReader = arrayReader; }
    }
    for (j = 0; j < rowReader.length; j++) {
      v = $.jgrid.getAccessor(cur, rowReader[j]);
      rd[ts.p.colModel[j + gi + si + ni].name] = v;
      rowData.push(addCell(idr, v, j + gi + si + ni, i + rcnt, cur, rd));
    }
    rowData[iStartTrTag] = constructTr(idr, hiderow, cn1, rd, cur, selr);
    rowData.push("</tr>");

    if (ts.p.grouping) {
      grpdata.push(rowData);
      if (!ts.p.groupingView._locgr) {
        groupingPrepare.call(self, rd, i);
      }
      rowData = [];
    }
    if (locdata || ts.p.treeGrid === true) {
      rd[locid] = $.jgrid.stripPref(ts.p.idPrefix, idr);
      ts.p.data.push(rd);
      ts.p._index[rd[locid]] = ts.p.data.length - 1;
    }

    // gridview 옵션 false 인경우 (기본값 false)
    if (ts.p.gridview === false) {
      // 그리드 body에 row(tr) 추가
      $("#" + $.jgrid.jqID(ts.p.id) + " tbody:first").append(rowData.join(''));
      // jqGridAfterInsertRow 트리거 이벤트 호출
      self.triggerHandler("jqGridAfterInsertRow", [idr, rd, cur]);
      // afterInsertRow 이벤트 호출
      if (afterInsRow) { ts.p.afterInsertRow.call(ts, idr, rd, cur); }
      rowData = [];//ari=0;
    }
    rd = {};
    ir++;
    i++;
    if (ir === rn) { break; }
  }

  // gridview 옵션 true 인경우 (기본값 false)
  if (ts.p.gridview === true) {
    fpos = ts.p.treeANode > -1 ? ts.p.treeANode : 0;
    if (ts.p.grouping) {
      if (!locdata) {
        self.jqGrid('groupingRender', grpdata, ts.p.colModel.length, ts.p.page, rn);
        grpdata = null;
      }
    } else if (ts.p.treeGrid === true && fpos > 0) {
      $(ts.rows[fpos]).after(rowData.join(''));
    } else {
      // 그리드에 row(tr) 추가
      ts.firstElementChild.innerHTML += rowData.join(''); // append to innerHTML of tbody which contains the first row (.jqgfirstrow)
      ts.grid.cols = ts.rows[0].cells; // update cached first row
    }
  }

  // subGrid 사용하는경우
  if (ts.p.subGrid === true) {
    try { self.jqGrid("addSubGrid", gi + ni); } catch (_) { }
  }
  ts.p.totaltime = new Date() - startReq;

  // records 옵션이 0인경우 데이터의 갯수 값으로 변경
  if (ir > 0) {
    if (ts.p.records === 0) { ts.p.records = len; }
  }
  rowData = null;

  // 트리그리드 사용하는경우
  if (ts.p.treeGrid === true) {
    try { self.jqGrid("setTreeNode", fpos + 1, ir + fpos + 1); } catch (e) { }
  }
  ts.p.reccount = ir;
  ts.p.treeANode = -1;

  // userDataOnFooter 옵션 - true 설정 시 userData를 footer에 배치시킴 (기본값: false)
  if (ts.p.userDataOnFooter) { self.jqGrid("footerData", "set", ts.p.userData, true); }

  // 위에서 지정한 변수 locdata = (ts.p.datatype !== "local" && ts.p.loadonce) || ts.p.datatype === "jsonstring";
  if (locdata) {
    ts.p.records = len;
    ts.p.lastpage = Math.ceil(len / rn);
  }

  // pager 업데이트
  if (!more) { ts.updatepager(false, true); }

  // 위에서 지정한 변수 locdata = (ts.p.datatype !== "local" && ts.p.loadonce) || ts.p.datatype === "jsonstring";
  if (locdata) {
    while (ir < len && drows[ir]) {
      cur = drows[ir];
      idr = $.jgrid.getAccessor(cur, idn);
      if (idr === undefined) {
        if (typeof idn === "number" && ts.p.colModel[idn + gi + si + ni] != null) {
          // reread id by name
          idr = $.jgrid.getAccessor(cur, ts.p.colModel[idn + gi + si + ni].name);
        }
        if (idr === undefined) {
          idr = br + ir;
          if (f.length === 0) {
            if (dReader.cell) {
              var ccur2 = $.jgrid.getAccessor(cur, dReader.cell) || cur;
              idr = ccur2 != null && ccur2[idn] !== undefined ? ccur2[idn] : idr;
              ccur2 = null;
            }
          }
        }
      }
      if (cur) {
        idr = ts.p.idPrefix + idr;
        rowReader = objectReader;
        if (dReader.repeatitems) {
          if (dReader.cell) { cur = $.jgrid.getAccessor(cur, dReader.cell) || cur; }
          if ($.isArray(cur)) { rowReader = arrayReader; }
        }

        for (j = 0; j < rowReader.length; j++) {
          rd[ts.p.colModel[j + gi + si + ni].name] = $.jgrid.getAccessor(cur, rowReader[j]);
        }
        rd[locid] = $.jgrid.stripPref(ts.p.idPrefix, idr);
        if (ts.p.grouping) {
          groupingPrepare.call(self, rd, ir);
        }
        ts.p.data.push(rd);
        ts.p._index[rd[locid]] = ts.p.data.length - 1;
        rd = {};
      }
      ir++;
    }
    if (ts.p.grouping) {
      ts.p.groupingView._locgr = true;
      self.jqGrid('groupingRender', grpdata, ts.p.colModel.length, ts.p.page, rn);
      grpdata = null;
    }
  }
}


위의 로직을 보면 addJSONData 메소드는 다음 두가지 기능을 한다.
 1) 넘겨받은 데이터를 그리드 body에 보여줌
 2) Pager 업데이트


하지만 아쉽게도 데이터를 그리드 내부에 저장하는 로직이 들어있지 않아 페이지 이동을 하거나 컬럼헤더를 클릭하여 정렬 기능을 사용하면 원래 데이터로 돌아가 버린다.
(처음에 데이터가 없다면 빈그리드가 나타날 것이다.)

위의 주의해야 할 사항때문에 특별한 경우에만 이 메소드를 사용할 수 있을것 같다.

datatype:'local' 인 경우 addJSONData 보다는 아래 두가지 방법중에 하나를 사용하는게 더 편하지 않을까 싶다.
 - addRowData 메소드로 row를 하나씩 추가
 - setGridParams 메소드로 data를 업데이트하고 reload



댓글