jqGrid フッター、ヘッダーに集計値表示

[ フッター配置例 ]

[ ヘッダー配置例 ]

[ jqGrid コード例 ]

デフォルトはフッター
footerrow, userDataOnFooter を true にする


footerrow: true,
userDataOnFooter: true,

ヘッダーにしたい時は、gridComplete で DOM操作して明細行と合計行の位置を入れ替える


  // フッター合計を上にする, 境界線スタイルを変える //
  var dtlobj = $('#gview_asivlist').children('div').eq(3);   // 明細行
  var fttlobj = $('#gview_asivlist').children('div').eq(4);  // 合計行
  $(fttlobj).css({
    "border-bottom-style": "solid",
    "border-bottom-color": '#008600',
    "border-bottom-width": "2px"
  }).insertBefore($(dtlobj));

[ Servlet コード例 ]

集計値用マップ


    // +++ 結果メッセージ用 +++ //
    HashMap<String, String> usrdata = new HashMap<String, String>();

検索後、集計値を格納


  /**
   * テーブルスキーマ情報取得
   *
   * @param usrdata 合計値マップ
   * @return テーブルスキーマ型リスト
   */
  public ArrayList<TableSchema> getTableSchemaList(HashMap<String, String> usrdata) {

    List list = null;
    try (SqlSession session = sqlSessionFactory.openSession()) {

      list = session.selectList("selTableSchemaList", this);
      System.out.println("getTableSchemaList ():" + list.size());

      // フッター用 //
      // ストリームで合計を格納 //
      ArrayList<TableSchema> slist = new ArrayList(list);
      int cntRow = (int)slist.stream().count();    // 件数 long なので intにキャスト     
      int colTotal = slist.stream().mapToInt(v -> v.getCntCol()).sum();     // 列数
      int rowTotal = slist.stream().mapToInt(v -> v.getCntRow()).sum();     // 行数
      int totalTotal = slist.stream().mapToInt(v -> v.getLenTotal()).sum(); // 合計サイズ
      int dataTotal = slist.stream().mapToInt(v -> v.getLenData()).sum();   // データサイズ
      int indexTotal = slist.stream().mapToInt(v -> v.getLenIndex()).sum(); // インデックスサイズ
      
      // HashMapに追加 //
      usrdata.put("cntCol", String.valueOf(colTotal));
      usrdata.put("cntRow", String.valueOf(rowTotal));
      usrdata.put("lenTotal", String.valueOf(totalTotal));
      usrdata.put("lenData", String.valueOf(dataTotal));
      usrdata.put("lenIndex", String.valueOf(indexTotal));
      usrdata.put("comment", "    Total " + String.valueOf(cntRow) + " Tables" );
      
    }
    catch (Exception se) {
      se.printStackTrace();
    }
    return new ArrayList(list);

  }

応答JSONのセット


    // +++ 結果返却用 +++ //
    JSONResultGrid loggrid = new JSONResultGrid();
    loggrid.setPage(1);
    loggrid.setTotal(1);
    loggrid.setRows(loglist);
    loggrid.setUserdata(usrdata);

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String gsonstr = gson.toJson(loggrid);

応答データ


  "userdata": {
    "cntRow": "27494440",
    "lenTotal": "4135942",
    "cntCol": "1689",
    "lenData": "2479938",
    "comment": "    Total 173 Tables",
    "lenIndex": "1656004",
    "sidx": "1"
  }

jqGrid タイトルセルに画像を配置

タイトル行の各thタグの id は、gridのid + “_” + colModelのnameプロパティ になっていて、textはcolNames配列の値となってますので、idを指定して、html を置き換えれば出来ます。

[ コード例 ]


// 国旗スパン //
var FLAG_SPAN = '<span><img src="Img/flag/TH.gif" /><span style="margin-left:4px;">HSCD</span></span>';

// HSCDに国旗をつける //
$('#' + $(this).attr('id') + '_cdHST').html(FLAG_SPAN);

[ 画面例 ]

MySQL 日付指定年齢関数

誕生年月日を渡せば、今日の年齢を返します。


CREATE DEFINER=`root`@`localhost` FUNCTION `fc_age_by_birthdate`(
	`bdate` date

)
RETURNS int(11)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT '日付値指定年齢取得スカラー関数'
begin
  declare agetoday int;
  select year(current_date) - year(bdate) - (right(current_date, 5) < right(bdate, 5)) into agetoday;
  return agetoday;
  
end

DATE型値をキャストなしで部分文字列取得できます。

下は今日以外を指定した年齢取得


CREATE DEFINER=`root`@`localhost` FUNCTION `fc_age_by_birthdate_tgtdt`(
	`bdate` date,
	`tgtdt` date
)
RETURNS int(11)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT '日付値指定年齢取得スカラー関数'
begin
  declare agetoday int;
  select year(tgtdt) - year(bdate) - (right(tgtdt, 5) < right(bdate, 5)) into agetoday;
  return agetoday;
  
end

[ 利用場面 ]

jqGrid インライン編集 extraparamのセット

最近、やっとわかったこととして、編集列として設定してないデータを更新用として送信する場合、以前は id に文字列表現したり、隠し列設定したりして、目的は達成できるものの、列が増えたりして、ややこしいプログラムになったりしてました。

editParams , addParams の中に extraparam をセットすれば、すっきりわかりやすくなります。

[ コード例 ]


// -- 編集 -- // 
editParams: {

  extraparam: {
    idUser: function () {
      return userid;
    }
  },
// -- 追加 -- //
addParams: {

  addRowParams: {
    extraparam: {
      cdJan: function () {
        return subgrid_table_id.split("_")[1];
      },
      idUser: function () {
        return userid;
      }
    },

編集送信データ例
idUser の列はないが、ちゃんと送信されたのがわかる

画面例

jqGrid 罫線 フォント色の動的設定

 

 

 

 

固定的に列のフォント色なんかを設定したい場合は、colModel の classes に CSSのクラス名なんかを設定しておけば、コーディングする必要ないですが、

動的なことする場合は、loadComplete で DOMのCSS設定したりします。

[ サンプルコード ]


// == グリッドデータ取得 == //
var rows = $(this).getRowData();

// == userdata取得 == //
var userdata = $(this).jqGrid('getGridParam', 'userData');

// 区切線用 //
var ulineidxary = [];

if (userdata['sidx'] == 'dceta' || userdata['sidx'] == 'vessel' || userdata['sidx'] == 'berth') {
  var rowsary = $(this).getRowData();
  var wcntary = [];
  $.each(rowsary, function (i, itm) {
    //wcntary.push(itm['dcetawdiff']);
    wcntary.push(itm[lineMap[userdata['sidx']]]);
  });

  $.each(wcntary, function (i, itm) {
    if (i > 0 && wcntary[i] != wcntary[i - 1]) {
      ulineidxary.push(i - 1);
    }
  });
  //$('#divdbg').text(ulineidxary);

}

// ++ 全行走査 ++ //
$.each(rows, function (i, itm) {
	 // VOY列右をに縦線を引く //
	$("#" + rows[i]['id'] + " td").eq(2).css("border-right-color", "#224444");
	
	// 週区切り線 //
	if (ulineidxary.indexOf(i) != -1) {
	  $("#" + rows[i]['id'] + " td").css("border-bottom-color",
	          !isDarkTheme ? "#004400" : "#99DD99");
	}
	
	// 船スペックタイトル //
	td = $('#' + rows[i]['id']).children('td').eq(1);
	$(td).attr('title', rows[i]['cnt'] + ' Records exists by this vessel.' + '\n' +
	        rows[i]['vesselspec']);
	
	// カレントポジションリンク用IMOタイトル //
	curimo = rows[i]['vesselspec'].replace("\n", "").slice(-8);
	td = $('#' + rows[i]['id']).children('td').eq(2);
	$(td).attr('title', curimo);
	
	// バース日がETAより大きい場合、赤文字ワーニング //
	etaschMD = !isOld ? rows[i]['dceta'].slice(0, 5) : rows[i]['dceta'].slice(3, 8);
	berthMD = rows[i]['tmberth'].slice(0, 5);
	
	if (berthMD > etaschMD) {
	  td = $('#' + rows[i]['id']).children('td').eq(BERTHTIME_COLIDX);
	  $(td).css('color', !isDarkTheme ? '#ff0000' : '#ff90ff');
	}
	// 早いのは青表示 //
	if (berthMD < etaschMD) { td = $('#' + rows[i]['id']).children('td').eq(BERTHTIME_COLIDX); $(td).css('color', !isDarkTheme ? '#0000aa' : '#00ffff'); } // 入港日差 遅れを赤表示 // if (rows[i]['difdceta'] > 0) {
	  td = td = $('#' + rows[i]['id']).children('td').eq(ETADIFF_COLIDX);
	  $(td).css('color', !isDarkTheme ? '#ff0000' : '#ff90ff');
	  //$(td).css('color', 'red');
	}
	// 入港日差 早いのは青表示 //
	if (rows[i]['difdceta'] < 0) {
	  td = td = $('#' + rows[i]['id']).children('td').eq(ETADIFF_COLIDX);
	  $(td).css('color', !isDarkTheme ? '#0000aa' : '#00ffff');
	}
	
	// SKIP行 //
	if (rows[i]['tmport'].indexOf('SKIP') != -1) {
	  $("#" + rows[i]['id'] + " td").addClass('td_lv');
	}
	
});	

画面例

jqGrid colModel, colNames (基本)

jqGridのcolNames, colModel については、下サンプルのようにプロパティで設定します。
先に変数に入れて、それを指定してもよいです。

本家 API : http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options

[ colModelインライン記述例 ]


datatype: "json",
loadui: 'block',
reloadAfterSubmit: true,
colNames: ['', 'Name', 'Home URL', 'My URL', 'Exp', 'Imp', 'LastUpdate', '', ''],
colModel: [
  {name: 'ico', width: '20px', align: 'center', classes: 'curpo'},
  {name: 'ope', width: '40px', align: 'left', classes: 'curpo'},

  {name: 'url', width: '120px', align: 'left', editable: true},
  {name: 'myurl', width: '120px', align: 'left', editable: true},

  {name: 'expcnt', width: '20px', align: 'right'},
  {name: 'impcnt', width: '20px', align: 'right'},
  {name: 'tmLastupdt', width: '50px', align: 'left', classes: 'tmcol'},
  {name: 'id', index: 'id', width: '0px', align: 'left',
    hidden: true,
    editrules: {edithidden: true}},
  {name: 'opeforedit', width: '0px', align: 'left', editable: true}
],
multiselect: false,

変数指定例


      var colnames = ['SKNo.', 'InvoiceNo.', '工場',  '揚港', 'コンテナNo.', '保税地域',
        '仕入額$', '仕入額\\', '納品日', '納品場所', '支払日', '請求額(課税)', '請求額(非課税)',
        '消費税', '税関名', '関税', '申告番号', '',
        '輸入諸掛(社内)', '輸入諸掛金額', '海上運賃', 'その他諸掛', '保険', '控除後売上', '粗利',
        '備考',  '最終更新', '', '', '', ''];

      var colmodel = [
        // SK No. //
        {name: 'noSK', index: 'NO_SK', width: '38px', align: 'left'},
        // Invoice No. //
        {name: 'noInv', index: 'NO_INV', width: '60px', align: 'left'},
        // 工場 //
        {name: 'nmFact', index: 'NM_FACT', width: '38px', align: 'left'},
        // DCPort //
        {name: 'nmDc', index: 'NM_DC', width: '20px', align: 'left'},
        // コンテナNo //
        {name: 'nmCont', index: 'NM_CONT', width: '64px', align: 'left'},

        // CYCFS 2018-09-28 //
        {name: 'cdTerminal', index: 'CD_TERMINAL', width: '40px', align: 'left', editable: true,
          edittype: "select",
          editoptions: {
            required: true,
            dataUrl: 'GetSelectTag?tp=cycfs',
            defaultValue: function (setval) {
              //setval = lastselIdxMap['cdCust'];
              return setval;
            }
          }
        },

        // ドル仕入額 //
        {name: 'amSuplusd', index: 'AM_SUPL_USD', width: '30px', align: 'right', editable: true,
          editrules: {number: true, minValue: 0, maxValue: 9999999}
        },
        // 円仕入額 //
        {name: 'amSupljpy', index: 'AM_SUPL_JPY', width: '30px', align: 'right', editable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 納品日 //
        {name: 'dtDeliv', index: 'DT_DELIV_LONG', width: '30px', align: 'center', "classes": "dtcol"},
        // 納品場所 //
        {name: 'nmDeliv', index: 'NM_DELIV', width: '50px', align: 'left'},
        // 支払日 //
        {name: 'dtPayment', index: 'DT_PAYMENT_LONG', width: '30px', align: 'center', editable: true, "classes": "dtcol"},
        // 課税請求 //
        {name: 'amInwithtax', index: 'AM_IN_WITH_TAX', width: '30px', align: 'right', editable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 非課税請求 //
        {name: 'amInnotax', index: 'AM_IN_NO_TAX', width: '30px', align: 'right', editable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 消費税 //
        {name: 'amTaxc', index: 'AM_TAXC', width: '30px', align: 'right'

        },
        // 税関名 //
        {name: 'nmCustom', index: 'NM_CUSTOM', width: '36px', align: 'left', editable: true,
          edittype: "select",
          editoptions: {
            required: true,
            dataUrl: 'GetSelectTag?tp=custom',
            defaultValue: function (setval) {
              //setval = lastselIdxMap['cdCust'];
              return setval;
            }
          }
        },
        // 関税 //
        {name: 'amTarrif', index: 'AM_TARRIF', width: '30px', align: 'right', editable: true, sotrable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 申告番号 //
        {name: 'noNotify', index: 'NO_NOTIFY', width: '56px', align: 'left', editable: true},
        // 通関チェック //
        {name: 'isCustomed', index: 'IS_CUSTOMED', width: '8px', align: 'center',
          editable: true,
          edittype: "checkbox", editoptions: {value: "1:0"}
        },
        // 輸入諸掛営業所名 //
        {name: 'nmDiv', index: 'NM_DIV', width: '38px', align: 'left', editable: true,
          edittype: "select",
          editoptions: {
            required: true,
            dataUrl: 'GetSelectTag?tp=divsk',
            defaultValue: function (setval) {
              //setval = lastselIdxMap['cdCust'];
              return setval;
            }
          }
        },
        // 輸入諸掛金額 //
        {name: 'amOutdiv', index: 'AM_OUT_DIV', width: '30px', align: 'right', editable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 海上運賃 //
        {name: 'amFreight', index: 'AM_FREIGHT', width: '30px', align: 'right', editable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // その他諸掛 //
        {name: 'amOther', index: 'AM_OTHER', width: '30px', align: 'right', editable: true},
        // 保険 //
        {name: 'amIns', index: 'AM_INS', width: '30px', align: 'right', editable: true,
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 控除後売上 //
        {name: 'amInfinal', index: 'AM_IN_FINAL', width: '30px', align: 'right', "classes": "cntcol",
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 粗利 //
        {name: 'amProfit', index: 'AM_PROFIT', width: '30px', align: 'right', "classes": "cntcol",
          editrules: {integer: true, minValue: 0, maxValue: 99999999}
        },
        // 備考 //
        {name: 'nmRemark', index: 'NM_REMARK', width: '40px', align: 'left', editable: true},
        // 最終更新 //
        {name: 'tmLastupdt', index: 'TM_LASTUPDT', width: '56px', align: 'center', classes: 'tmcol'},
        // 隠し列 //
        {name: 'id', width: '0px', editable: true, edithidden: true, hidden: true},
        {name: 'dtDelivlong', width: '0px', editable: true, edithidden: true, hidden: true},
        {name: 'dtPaymentlong', width: '0px', editable: true, edithidden: true, hidden: true},
        {name: 'txtOthers', width: '0px', editable: true, edithidden: true, hidden: true}
      ];

編集可能で列が多くなったりすると、ややこしく扱いにくくなるので、データベースから読み込んだりしてます。
データベースでの設定については、別途説明します。

jqGrid インライン編集 編集

[ コードサンプル ]


// ナビゲータの設定 //
	$("#opemaster").jqGrid('navGrid', "#opemasterpager",
        {edit: true, add: false, del: false});

// ++ インライン編集の設定 ++ //
$("#opemaster").jqGrid('inlineNav', "#opemasterpager", {
  edit: true,
  editicon: "ui-icon-pencil",
  // 編集 // 
  editParams: {
    oneditfunc: function (id) {     //選択行の編集時

      // フォーカス //
      $('#' + id + '_url').focus();
    },
    // 保存した後 //
    aftersavefunc: function (restxt) {
    },
    // 更新成功した時 //
    successfunc: function (resjsn, id) {

      // My URLはローカルストレージに保存する //
      //alert(JSON.stringify(resjsn));
      var resmap = JSON.parse(resjsn.responseText);
      //alert(resmap);

      if (resmap['myurl'] != null) {
        myurlMap[resmap['ope']] = resmap['myurl'];
        //alert(JSON.stringify(myurlMap));
        if (localStorage) {
          localStorage.setItem('vesselsch_myurlmap', JSON.stringify(myurlMap));
        }
      }
      // reloadAfterPostが効かないので入れる //
      $(this).jqGrid('setGridParam', {}).trigger('reloadGrid');
      //}
    }
  }
});

 

画面例

colModel


colNames: ['', 'Name', 'Home URL', 'My URL', 'Exp', 'Imp', 'LastUpdate', '', ''],
colModel: [
  {name: 'ico', width: '20px', align: 'center', classes: 'curpo'},
  {name: 'ope', width: '40px', align: 'left', classes: 'curpo'},

  {name: 'url', width: '120px', align: 'left', editable: true},
  {name: 'myurl', width: '120px', align: 'left', editable: true},

  {name: 'expcnt', width: '20px', align: 'right'},
  {name: 'impcnt', width: '20px', align: 'right'},
  {name: 'tmLastupdt', width: '50px', align: 'left', classes: 'tmcol'},
  {name: 'id', index: 'id', width: '0px', align: 'left',
    hidden: true,
    editrules: {edithidden: true}},
  {name: 'opeforedit', width: '0px', align: 'left', editable: true}
],

/* editable にした列が送信される */

送信データ例

jqGrod 折り畳み状態の永続化

たくさんのグリッドを配置したページでは、あまり見ないのは折り畳んでおくとすっきりしますが、次回使う時、開いた状態で始まるとわかりにくく、使いにくいので、ローカルストレージに保存して前回最終折り畳み状態を再現できるようにします。

[ コードサンプル ]


      //  各グリッド折り畳み状態 //
      /* キーはグリッドid, hiddngid が true or false 既定は全部trueで折り畳み   */
      var gdhiddenMap = {delayskip: true, pctgt: true, pchst: true, mtapi: true, usradd: true, tgtbps: true,
        tableschemalist: true, tableloglist: true, batlog: true,
        pcsum: true, apidoc: true, pcncann: true, svpdsterr: true, polydel: true, polyfacildel: true,
        bareaupdt: true, actcy: true};
        
      // ローカルストレージから読む //
      if (localStorage) {
        if (localStorage.getItem('vesselsch_gdstate_logshow') != null) {
          var hdnmap = JSON.parse(localStorage.getItem('vesselsch_gdstate_logshow'));
          /*for (key in gdhiddenMap) {
           if (hdnmap[key] !== undefined) {
           gdhiddenMap[key] = hdnmap[key];
           }
           }*/
          // これでも出来るが、あまり変わりないような //
          $.map(gdhiddenMap, function (value, index) {
            if (hdnmap[index] !== undefined) {
              gdhiddenMap[index] = hdnmap[index];
            }
          });
        }
      }
      
      
      /* jgGrid プロパティ設定 */
      hiddengrid: gdhiddenMap['delayskip'], // 折り畳み
      	
      /* jqGrid onHeaderClick イベントでローカルストレージに保存する */
      // -- 折り畳みを変えた時 -- //
          onHeaderClick: function () {
            var gdstate = $(this).jqGrid('getGridParam', 'gridstate');
            var thisid = $(this).attr('id');
            gdhiddenMap[thisid] = gdstate == 'hidden';
            localStorage.setItem('vesselsch_gdstate_logshow', JSON.stringify(gdhiddenMap));
          },	

Chromeの開発ツールで状態をチェックする

jqGrid セルに画像を配置

loadCompleteで行走査して、指定列番セルにhtmlで設定してます。


const var ANCH_SPAN = '<span style="margin-left:4px"/><img src="Img/port.png" /></span>';

              // 国旗 //
              // tdのセット //
              td = $('#' + rows[i]['id']).children('td').eq(FLG_COLIDX);
              if (rows[i]['cdCntry'] != '') {
                $(td).html(
                        '<span style="margin-left:2px"/><img src="Img/flag/' + rows[i]['cdCntry'] + '.gif" /></span>')
              }
              else if (rows[i]['lastpcres'].indexOf(' ANCH ') != -1) {
                $(td).html(ANCH_SPAN);
              }
              else {
                $.each(ANCH_ARY, function (j, itm) {
                  if (rows[i]['lastpcres'].indexOf(itm) != -1) {
                    $(td).html(ANCH_SPAN);
                  }
                });
              }

              // 入出港アイコン //
              td = $('#' + rows[i]['id'] + ' td').eq(ARVDEP_COLIDX);
              if (rows[i]['lastpcres'] != '') {
                $(td).html('<span style="margin-left:4px;margin-right:4px;"><img src="Img/ope/' +
                        (rows[i]['lastpcres'].slice(0, 3)) + '.png"/></span>');
              }

・動的設定はhidden列でしてる
・htmlが長くなるのはconstでセットするとよい

< 画面例 >