業務アプリ用dataTablesテンプレ
夏休みの自由研究として3日かけて、今までJsp/Servlet何度となく作って来たデータの一覧表示画面作成の経験を元に、よく求められる以下の要求を詰め込んでコピペで動作するdataTablesのテンプレを作ってみた。
- ページング
- チェックボックス/全選択
- 表示件数変更
- ソート
- 縦横スクロール
- CSVファイル出力
- 日時タイムスタンプを文字列化してファイル名生成
- ツールチップ表示
- 印刷
dataTablesとして対応した事は以下。
- 日本語化
- 全選択/全解除ボタン追加 デフォルトで用意されていないのでQuery DataTables Checkboxesを使用
- bootstrap5のレイアウト適用(罫線とページングのレイアウト)
- domによる部品の並び替え(一番面倒だった)
CSV出力なんて昔は毎度サーブレットを介して作っていたが、今ではそんなことをしなくてもクライアントサイドで片が付くことに時代の流れを感じる。dataTablesはかなり自由度が高いカスタマイズができるが故に、設定の概要を把握するのに時間を要した。
実際の表示
No. | ID | 名前 | 役職 | 配属 | 年齢 | 給料 |
---|
ソースコード
以下をローカルのhtmlファイルに張り付ければ現時点で動作します。
<!DOCTYPE html>
<html lang="ja">
<head>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.3.0/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/fixedcolumns/4.3.0/css/fixedColumns.dataTables.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/select/1.7.0/css/select.dataTables.min.css"/>
<link rel="stylesheet" type="text/css" href="https://gyrocode.github.io/jquery-datatables-checkboxes/1.2.12/css/dataTables.checkboxes.css" />
<script type="text/javascript" language="javascript" src="https://code.jquery.com/jquery-3.7.0.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/fixedcolumns/4.3.0/js/dataTables.fixedColumns.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/select/1.7.0/js/dataTables.select.min.js"></script>
<script type="text/javascript" language="javascript" src="https://gyrocode.github.io/jquery-datatables-checkboxes/1.2.12/js/dataTables.checkboxes.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/buttons/2.4.1/css/buttons.dataTables.min.css"/>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/buttons/2.4.1/js/dataTables.buttons.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/pdfmake.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.53/vfs_fonts.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.html5.min.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.print.min.js"></script>
<!-- 選択行の色反転をやめる場合、dataTables.selectのjsとcssを削除 -->
<!-- dataTables.checkboxes.min.jsの前にdataTables.select.min.js"を読み込まないと反転が正しく動かない -->
<style>
/* ヘッダの色 */
table.dataTable thead th {
background-color: lightskyblue;
}
/* 行選択色(偶数行) */
table.dataTable>tbody>tr.selected>* {
box-shadow: inset 0 0 0 9999px lightblue;
color: inherit;
}
/* 行選択色(奇数行) */
table.dataTable.table-striped>tbody>tr.odd.selected>* {
box-shadow: inset 0 0 0 9999px lightblue;
}
/* fixColumnsしたのヘッダの色 */
table.dataTable thead tr>.dtfc-fixed-left, table.dataTable thead tr>.dtfc-fixed-right, table.dataTable tfoot tr>.dtfc-fixed-left, table.dataTable tfoot tr>.dtfc-fixed-right {
background-color: lightskyblue;
}
/* fixColumns + scrollYした場合のbug対応 */
.dtfc-right-top-blocker{
display:none!important;
}
/* ボタンの大きさ */
div.dt-buttons>.dt-button, div.dt-buttons>div.dt-button-split .dt-button {
height: 31px;
padding-top: 3px;
margin-bottom: 0px;
}
/* 以降は部品の並び指定 */
div.dt-top-container {
display: grid;
grid-template-columns: auto auto;
}
div.dt-bottom-container {
display: grid;
grid-template-columns: auto auto;
}
div.dt-center-in-div {
margin: 0 auto;
}
div.dt-filter-spacer {
margin: 5px 0;
}
div.dt-buttons {
text-align: right;
width: 476px;
}
</style>
<script>
$(document).ready(function(){
// 日本語化
$.extend($.fn.dataTable.defaults, {
language: {
url: "https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Japanese.json"
}
});
// テストデータ
let testData = [
{ id : '0000001', name : 'Tiger Nixon', class : 'System Architect', aff : 'Edinburgh', age : 61, salary : '$320,800', },
{ id : '0000002', name : 'Garrett Wint', class : 'Accountant', aff : 'Tokyo', age : 63, salary : '$170,750', },
{ id : '0000003', name : 'Ashton Cox', class : 'Junior Technical Author', aff : 'San Francisco', age : 66, salary : '$86,000', },
{ id : '0000004', name : 'Cedric Kelly', class : 'Senior Developer', aff : 'Edinburgh', age : 22, salary : '$433,060', },
{ id : '0000005', name : 'Airi Satou', class : 'Accountant', aff : 'Tokyo', age : 33, salary : '$162,700', },
{ id : '0000006', name : 'Brielle William', class : 'Integration Specialist', aff : 'New York', age : 61, salary : '$372,000', },
{ id : '0000007', name : 'Herrod Chand', class : 'Sales Assistant', aff : 'San Francisco', age : 59, salary : '$137,500', },
{ id : '0000008', name : 'Rhona David', class : 'Integration Specialist', aff : 'Tokyo', age : 55, salary : '$327,900', },
{ id : '0000009', name : 'Colleen Hurst', class : 'Javascript Developer', aff : 'San Francisco', age : 39, salary : '$205,500', },
{ id : '0000010', name : 'Sonya Frost', class : 'Software Engineer', aff : 'Edinburgh', age : 23, salary : '$103,600', },
{ id : '0000011', name : 'Jena Gaines', class : 'Office Manager', aff : 'London', age : 30, salary : '$90,560', },
{ id : '0000012', name : 'Quinn Flynn', class : 'Support Lead', aff : 'Edinburgh', age : 22, salary : '$342,000', },
{ id : '0000013', name : 'Charde Marsh', class : 'Regional Director', aff : 'San Francisco', age : 36, salary : '$470,600', },
{ id : '0000014', name : 'Haley Kennedy', class : 'Senior Marketing Designer', aff : 'London', age : 43, salary : '$313,500', },
{ id : '0000015', name : 'Tatyana Fitz', class : 'Regional Director', aff : 'London', age : 19, salary : '$385,750', },
{ id : '0000016', name : 'Michael Silva', class : 'Marketing Designer', aff : 'London', age : 66, salary : '$198,500', },
{ id : '0000017', name : 'Paul Byrd', class : 'Chief Financial Officer', aff : 'New York', age : 64, salary : '$725,000', },
{ id : '0000018', name : 'Gloria Little', class : 'Systems Administrator', aff : 'New York', age : 59, salary : '$237,500', },
{ id : '0000019', name : 'Bradley Greer', class : 'Software Engineer', aff : 'London', age : 41, salary : '$132,000', },
{ id : '0000020', name : 'Dai Rios', class : 'Personnel Lead', aff : 'Edinburgh', age : 35, salary : '$217,500', },
{ id : '0000021', name : 'Jenette Caldwell', class : 'Development Lead', aff : 'New York', age : 30, salary : '$345,000', },
{ id : '0000022', name : 'Yuri Berry', class : 'Chief Marketing Officer (CMO)', aff : 'New York', age : 40, salary : '$675,000', },
{ id : '0000023', name : 'Caesar Vance', class : 'Pre-Sales Support', aff : 'New York', age : 21, salary : '$106,450', },
{ id : '0000024', name : 'Doris Wilder', class : 'Sales Assistant', aff : 'Sydney', age : 23, salary : '$85,600', },
{ id : '0000025', name : 'Angelica Ramos', class : 'Chief Executive Officer (CEO)', aff : 'London', age : 47, salary : '$1,200,000', },
{ id : '0000026', name : 'Gavin Joyce', class : 'Developer', aff : 'Edinburgh', age : 42, salary : '$92,575', },
{ id : '0000027', name : 'Jennifer Chang', class : 'Regional Director', aff : 'Singapore', age : 28, salary : '$357,650', },
{ id : '0000028', name : 'Brenden Wagner', class : 'Software Engineer', aff : 'San Francisco', age : 28, salary : '$206,850', },
{ id : '0000029', name : 'Fiona Green', class : 'Chief Operating Officer (COO)', aff : 'San Francisco', age : 48, salary : '$850,000', },
{ id : '0000030', name : 'Shou Itou', class : 'Regional Marketing', aff : 'Tokyo', age : 20, salary : '$163,000', },
{ id : '0000031', name : 'Michelle House', class : 'Integration Specialist', aff : 'Sydney', age : 37, salary : '$95,400', },
{ id : '0000032', name : 'Suki Burks', class : 'Developer', aff : 'London', age : 53, salary : '$114,500', },
{ id : '0000033', name : 'Prescott Bartlett', class : 'Technical Author', aff : 'London', age : 27, salary : '$145,000', },
{ id : '0000034', name : 'Gavin Cortez', class : 'Team Leader', aff : 'San Francisco', age : 22, salary : '$235,500', },
{ id : '0000035', name : 'Martena Mccray', class : 'Post-Sales support', aff : 'Edinburgh', age : 46, salary : '$324,050', },
{ id : '0000036', name : 'Unity Butler', class : 'Marketing Designer', aff : 'San Francisco', age : 47, salary : '$85,675', },
{ id : '0000037', name : 'Howard Hatfield', class : 'Office Manager', aff : 'San Francisco', age : 51, salary : '$164,500', },
{ id : '0000038', name : 'Hope Fuentes', class : 'Secretary', aff : 'San Francisco', age : 41, salary : '$109,850', },
{ id : '0000039', name : 'Vivian Harrell', class : 'Financial Controlle', aff : 'San Francisco', age : 62, salary : '$452,500', },
{ id : '0000040', name : 'Timothy Mooney', class : 'Office Manager', aff : 'London', age : 37, salary : '$136,200', },
{ id : '0000041', name : 'Jackson Bradshaw', class : 'Director', aff : 'New Yor', age : 65, salary : '$645,750', },
{ id : '0000042', name : 'Olivia Liang', class : 'Support Engineer', aff : 'Singapore', age : 64, salary : '$234,500', },
{ id : '0000043', name : 'Bruno Nash', class : 'Software Engineer', aff : 'London', age : 38, salary : '$163,500', },
{ id : '0000044', name : 'Sakura Yamamoto', class : 'Support Engineer', aff : 'Tokyo', age : 37, salary : '$139,575', },
{ id : '0000045', name : 'Thor Walton', class : 'Developer', aff : 'New York', age : 61, salary : '$98,540', },
{ id : '0000046', name : 'Finn Camacho', class : 'Support Engineer', aff : 'San Francisco', age : 47, salary : '$87,500', },
{ id : '0000047', name : 'Serge Baldwin', class : 'Data Coordinator', aff : 'Singapore', age : 64, salary : '$138,575', },
{ id : '0000048', name : 'Zenaida Frank', class : 'Software Engineer', aff : 'New York', age : 63, salary : '$125,250', },
{ id : '0000049', name : 'Zorita Serrano', class : 'Software Engineer', aff : 'San Francisco', age : 56, salary : '$115,000', },
{ id : '0000050', name : 'Jennifer Acosta', class : 'Junior Javascript Developer', aff : 'Edinburgh', age : 43, salary : '$75,650', },
{ id : '0000051', name : 'Cara Stevens', class : 'Sales Assistant', aff : 'New York', age : 46, salary : '$145,600', },
{ id : '0000052', name : 'Hermione Butler', class : 'Regional Director', aff : 'London', age : 47, salary : '$356,250', },
{ id : '0000053', name : 'Lael Greer', class : 'Systems Administrator', aff : 'London', age : 21, salary : '$103,500', },
{ id : '0000054', name : 'Jonas Alexander', class : 'Developer', aff : 'San Francisco', age : 30, salary : '$86,500', },
{ id : '0000055', name : 'Shad Decker', class : 'Regional Director', aff : 'Edinburgh', age : 51, salary : '$183,000', },
{ id : '0000056', name : 'Michael Bruce', class : 'Javascript Developer', aff : 'Singapore', age : 29, salary : '$183,000', },
{ id : '0000057', name : 'Donna Snider', class : 'Customer Support', aff : 'New York', age : 27, salary : '$112,000', },
];
$('#table1').DataTable({
data: testData,
columnDefs: [
// チェックボックス https://www.gyrocode.com/projects/jquery-datatables-checkboxes/
{
targets: 0,
width: "20px",
checkboxes: {
selectRow: true,
},
},
// 行番号
{
targets: 1,
searchable: false, // 簡易検索の対象外
orderable: false, // ソートしない
width: "25px",
},
// ID
{ targets: 2, data: 'id', width: "45px", },
// 名前
{
targets: 3,
data: 'name',
width: "115px",
render: function(data, type, row) {
// 配属先ツールチップ表示
return '<a href="javascript:void(0)" title="配属:'+row[5]+'" style="color:inherit;text-decoration:none;">'+data+'</a>';
},
},
// 役職
{ targets: 4, data: 'class', width: "180px", },
// 配属 ※非表示
{ targets: 5, data: 'aff', visible: false },
// 年齢
{ targets: 6, data: 'age', width: "39px",},
// 給料
{ targets: 7, data: 'salary', },
// 空行があるのでjsonデータのカラム数と合わない問題の対策:Datatables Requested unknown parameter ‘0’ for row 0, column 0
{
defaultContent: " ",
targets: "_all",
}
],
rowId: 'id', // 行idをtargets:2のIDとする
select: {
style: 'multi', // ラジオボタン化する時はsingle
info: false // テーブル下に表示されるn row selectedの表示を非表示
},
order: [[2, 'asc']], // 初期ソート列
scrollCollapse: true, // データ増減による縦幅の伸縮
scrollX: true, // 横スクロール有無
scrollY: '837px', // 縦スクロール幅
fixedColumns: { // 横スクロール時の列固定
leftColumns: 4,
},
lengthMenu: [ // 選択件数
[20, 50, 100, -1],
[20, 50, 100, '全件']
],
dom: '<"dt-top-container"<l><"dt-center-in-div"B>r>t<"dt-filter-spacer"><"dt-bottom-container"ip>', // 部品の並び
buttons: [
{
extend: 'csvHtml5',
text: 'CSV出力',
bom: true,
filename: function() {
// 日時タイムスタンプを文字列化してファイル名生成
let d = new Date(),
yyyy = d.getYear() + 1900,
MM = ('0' + (d.getMonth() + 1)).slice(-2),
dd = ('0' + d.getDate()).slice(-2),
hh = ('0' + d.getHours()).slice(-2),
mm = ('0' + d.getMinutes()).slice(-2),
ss = ('0' + d.getSeconds()).slice(-2),
SSS = ('00' + d.getMilliseconds()).slice(-3);
return 'drg75datatableSample_' + yyyy + MM + dd + hh + mm + ss + SSS;
},
exportOptions: {
columns: ':visible:not(:eq(0))', // 先頭の列を出力しない
modifier: {
selected: false, // 選択状態に関わらず出力
search: 'none' // 簡易検索時の反映を無視
},
}
},
// { extend: 'pdfHtml5', text: 'PDF出力', }, // 要文字化け対策、GitHub naoa/pdfmakeのvfs_fonts.jsが必要
{
extend: 'print',
text: '印刷', title:
'印刷サンプル',
search: 'none',
exportOptions: {
columns: ':visible:not(:eq(0))', // 先頭の列を出力しない
modifier: {
selected: false, // 選択状態に関わらず出力
page: 'current', // 現在ページのみ出力
search: 'none' // 簡易検索時の反映を無視
},
}
}
]
});
// 列:No.の行番号採番
$('#table1').DataTable().on('order.dt search.dt', function() {
let i = 1;
$('#table1').DataTable().cells(null, 1, { search: 'applied', order: 'applied' }).every(
function (cell) {
this.data(i++);
}
);
}).draw();
});
// 選択行表示
function check(){
let selected = $('#table1').DataTable().rows({selected: true}).ids();
if (selected.length != 0) {
$('#selected').html('ID:' + $('#table1').DataTable().rows({selected: true}).ids().join(', ') + ' が選択されています。');
} else {
$('#selected').html('選択されていません。');
}
}
</script>
<title>dataTable sample/demo</title>
</head>
<body>
<button type="button" onclick="check();" style="height: 31px;padding-top: 3px;padding: 0em 1em;border: 1px solid rgba(0, 0, 0, 0.3); font-size: .88em;background: linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);">確認</button>
<br />
<div id="selected" style="width:560px;margin-top:5px;margin-bottom:5px;color:blue;"> </div>
<hr style="margin-top:0px;margin-bottom:6px;width:600px;" />
<div style="width:600px">
<table id="table1" class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th>No.</th>
<th>ID</th>
<th>名前</th>
<th>役職</th>
<th>配属</th>
<th>年齢</th>
<th>給料</th>
</tr>
</thead>
</table>
</div>
</body>
</html>
<!-- created by drg75.com -->
レイアウト変更例(簡易検索追加)
div.dt-top-container {
display: grid;
grid-template-columns: auto auto;
}
↓
div.dt-top-container {
display: grid;
grid-template-columns: auto auto auto;
}
div.dt-buttons {
text-align: right;
width: 476px;
}
↓
div.dt-buttons {
text-align: right;
width: 253px;
}
div.dataTables_wrapper div.dataTables_filter label {
text-align: left;
margin-left: 8px;
}
dom: '<"dt-top-container"<l><"dt-center-in-div"B>r>t<"dt-filter-spacer"><"dt-bottom-container"ip>',
↓
dom: '<"dt-top-container"<l><f><"dt-center-in-div"B>r>t<"dt-filter-spacer"><"dt-bottom-container"ip>',
#datatables Examples
#datatables Sample
#datatables Demo
#datatables checkboxes
#datatables all select
コメント