티스토리 뷰
tabulator
http://tabulator.info/ 라이브러리
테이블 안에 테이블 ( row - expand ) ajax 기능을 구현
html, script
버그수정
2018. 07. 19
자식 테이블 로드하고 [ 열림 - 닫힘 ] 누르고 부모테이블 페이지 이동하면 문제없는데
자식 테이블 로드하고 [ 열림 ] 상태로 부모테이블 페이지 이동하면 에러 나는 문제 해결
2018. 07. xx
한번 생성된 자식 테이블은 id나 ( id가 없으면 그냥 row.index로 라도 배열 element 부여한다..) 해서
전역배열에 tabulator 인스턴스 저장하고 재 생성을 방지, 닫힘 누르면 destroy 한다.
2018. 07 xx
formatter 함수를 쓸 경우, renderComplete callback으로 추후에 선언될 스크립트 기능에 대해서
호출해야 함.
<!DOCTYPE html>
<html lang='ko'>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="refresh" content="43200"><!-- 12hours 43200 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" />
<meta name="description" content="serpiko's HTML5 Template ver 2016.11.02" />
<meta name="author" content="serpiko@hanmail.net ( http://serpiko.tistory.com )" />
<!--
<link rel="shortcut icon" href="favicon.ico">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
-->
<title>Document</title>
<!-- css -->
<!--<link rel="stylesheet" type="text/css" href="/assets/css/style.css" />-->
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<link href="dist/css/tabulator.min.css" rel="stylesheet">
<link href="font-awesome-4.7.0/css/font-awesome.min.css" rel='stylesheet'>
<style>
* {
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
#wrap{
padding:10px;
}
.m-t-10{
margin-top: 10px;
}
.m-b-10{
margin-bottom: 10px;
}
.font-red{
color: #FF0000;
}
</style>
</head>
<body>
<div id="wrap">
<div class='m-t-10 m-b-10'>
Page: <select class='table-pagenation'>
<option value='5'>5</option>
<option value='10'>10</option>
<option value='20'>20</option>
<option value='30'>30</option>
</select>
<button type='button' id='download-xlsx'>download-xlsx</button>
<button type='button' id='download-pdf'>download-pdf</button>
Field:
<select id="filter-field">
<option></option>
<option value="name">Name</option>
<option value="progress">Progress</option>
<option value="gender">Gender</option>
<option value="rating">Rating</option>
<option value="col">Favourite Colour</option>
<option value="dob">Date Of Birth</option>
<option value="car">Drives</option>
<option value="function">Drives &Rating < 3</option>
</select>
Type:
<select id="filter-type">
<option value="=">=</option>
<option value="<"><</option>
<option value="<="><=</option>
<option value=">">></option>
<option value=">=">>=</option>
<option value="!=">!=</option>
<option value="like">like</option>
</select>
Value:
<input id="filter-value" type="text" placeholder="value to filter">
<button type='button' id='filter-clear'>Clear Filter</button>
<button type='button' id="refresh">refresh</button>
</div>
<div id="example-table"></div>
</div>
<!-- script -->
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script type="text/javascript" src="dist/js/tabulator.min.js"></script>
<script type="text/javascript" src="http://oss.sheetjs.com/js-xlsx/xlsx.full.min.js"></script>
<script>
$(document).ready(function(){
//////////////////////////////
var _arrRowSelected_ID = [];
var _arrRowSelected_NAME = [];
var _lastSelected_NAME = "";
// child table 배열
var _arrPrevTableEl = [];
// 중복된 배열을 검사하여 삭제 ( 토글했을때 삭제해줘야 하기 떄문에 )
function duplicateArraySplice($element, $array){
var index = $array.indexOf($element);
if( -1 === index ) $array.push($element);
else $array.splice(index, 1);
}
// 테이블의 현재 페이지를 reload 한다
function currentPageReload($tgId){
var currentPage = $tgId.tabulator("getPage");
$tgId.tabulator("setPage", currentPage);
//$tgId.tabulator("setData");
}
//Generate print icon
var printIcon = function(cell, formatterParams){ //plain text value
return "<i class='fa fa-lg fa-plus-circle'></i>";
};
$("#example-table").tabulator({
//height:205, // set height of table (in CSS or here), this enables the Virtual DOM and improves render speed dramatically (can be any valid css height value)
height:"100%",
layout:"fitDataFill",
movableColumns:true,
tooltips:true,
resizableRows:true,
pagination:"remote",
ajaxURL:"exampledata2.php",
ajaxConfig:"POST",
ajaxParams:{func:"first_data"},
paginationSize:5,
placeholder:"No Data Set",
columns:[
{formatter:printIcon, field:"detail", width:40, align:"center", resizable:false, headerSort:false, "cellClick":cellClick},
{title:"Name", field:"name", sorter:"string", width:200, "cellClick":cellClick},
{title:"Progress", field:"progress", sorter:"number", formatter:"progress"},
{title:"Gender", field:"gender", sorter:"string"},
{title:"Rating", field:"rating", formatter:"star", align:"center", width:100},
{title:"Favourite Color", field:"col", sorter:"string", sortable:false},
{title:"Date Of Birth", field:"dob", sorter:"date", align:"center"},
{title:"Driver", field:"car", align:"center", formatter:"tickCross", sorter:"boolean", "cellClick":cellClick},
],
// 지속성 옵션
persistentLayout : false, // 열 레이아웃 지속성 사용
persistentSort : false, // 정렬 지속성 사용
persistentFilter : false,
selectablePersistence : false , // 롤링 선택 해제
//선택
selectable:true,
/*
rowClick:function(e, row){ //trigger an alert message when the row is clicked
//row.toggleSelect();
var id = row.getData().id;
var name = row.getData().name;
//
duplicateArraySplice(id, _arrRowSelected_ID);
duplicateArraySplice(name, _arrRowSelected_NAME);
//
_lastSelected_NAME = row.getData().name;
// logs
console.group("row info");
console.log( '_arrRowSelected_ID:[ ' + _arrRowSelected_ID +' ]' );
console.log( '_lastSelected_NAME:[ ' + _lastSelected_NAME +' ]' );
console.log( '_arrRowSelected_NAME:[ ' + _arrRowSelected_NAME +' ]' );
console.groupEnd();
}
*/
ajaxRequesting: function(){
var key = Object.keys(_arrPrevTableEl);
if( 0 < _arrPrevTableEl.length){
if( null != _arrPrevTableEl[key] || "undefined" != typeof _arrPrevTableEl[key] ){
_arrPrevTableEl[key].tabulator('destroy');
_arrPrevTableEl[key] = null;
}
}
},
});
// 출력할 데이터 개수 변경
$(".table-pagenation").on("change", function(e){
var value = parseInt( $(e.currentTarget).val(), 10 );
$("#table").tabulator("setPageSize", value);
});
//trigger download of data.xlsx file
$("#download-xlsx").click(function(){
$("#example-table").tabulator("download", "xlsx", "data.xlsx", {sheetName:"My Data"});
});
//trigger download of data.pdf file
$("#download-pdf").click(function(){
$("#example-table").tabulator("download", "pdf", "data.pdf", {
orientation:"portrait", //set page orientation to portrait
title:"Example Report", //add title to report
});
});
$("#refresh").click(function(){
currentPageReload( $("#example-table") );
});
//Custom filter example
function customFilter(data){
return data.car && data.rating < 3;
}
//Trigger setFilter function with correct parameters
function updateFilter(){
var filter = $("#filter-field").val() == "function" ? customFilter : $("#filter-field").val();
if($("#filter-field").val() == "function" ){
$("#filter-type").prop("disabled", true);
$("#filter-value").prop("disabled", true);
}else{
$("#filter-type").prop("disabled", false);
$("#filter-value").prop("disabled", false);
}
$("#example-table").tabulator("setFilter", filter, $("#filter-type").val(), $("#filter-value").val());
}
//Update filters on value change
$("#filter-field, #filter-type").change(updateFilter);
$("#filter-value").keyup(updateFilter);
//Clear filters on "Clear Filters" button click
$("#filter-clear").click(function(){
$("#filter-field").val("");
$("#filter-type").val("=");
$("#filter-value").val("");
$("#example-table").tabulator("clearFilter");
});
function cellClick(e, cell){
//cell.getData()
var $tgEl = $(e.currentTarget),
$rowEl = $tgEl.parent(),
rowIdx,
//
holderEl,
buttonEl,
tableEl;
/**
* rowIdx
* id [ intrger ] 로 각 데이터 번호를 unique 하게받아서 사용 => 배열에 사용할 값
* 만약 없다면 그냥 row 순서로 사용한다..
*/
rowIdx = cell.getRow().getData().id;
if( typeof rowIdx == "undefined" ){
rowIdx = parseInt($rowEl.index(), 10);
}
//
if( null == _arrPrevTableEl[rowIdx] ){
//create and style holder elements
holderEl = $("<div class='holderEl'></div>");
buttonEl = $("<div class='buttonEl m-b-5'><button type='button' class='btn btn-success m-r-5 add_btn'>서버등록</button><button type='button' class='btn btn-danger del_btn'>삭제</button>");
tableEl = $("<div></div>");
holderEl.css({
"display":"none",
"box-sizing":"border-box",
"padding":"10px 30px 10px 10px",
"border-top":"1px solid #333",
"border-bottom":"1px solid #333",
"background":"#ddd",
});
holderEl.append(buttonEl);
holderEl.append(tableEl);
cell.getRow().getElement().append(holderEl);
$tgEl.find("i").removeClass("fa-plus-circle").addClass("fa-minus-circle font-red");
$(holderEl).slideDown();
//
_arrPrevTableEl[rowIdx] = tableEl.tabulator({
height:"100%",
layout:"fitDataFill",
movableColumns:true,
tooltips:true,
pagination:"remote",
ajaxURL:"exampledata.php",
ajaxConfig:"POST",
ajaxParams:{func:"second_data"},
paginationSize:5,
placeholder:"No Data Set",
columns:[
{title:"id", field:"id", visible:false},
{title:"Name", field:"name", sorter:"string", width:200},
{title:"Progress", field:"progress", sorter:"number", formatter:"progress"},
{title:"Gender", field:"gender", sorter:"string"},
{title:"Rating", field:"rating", formatter:"star", align:"center", width:100},
{title:"Favourite Color", field:"col", sorter:"string", sortable:false},
{title:"Date Of Birth", field:"dob", sorter:"date", align:"center"},
{title:"Driver", field:"car", align:"center", formatter:"tickCross", sorter:"boolean"},
],
//선택
selectable:true,
rowClick:function(e, row){ //trigger an alert message when the row is clicked
//row.toggleSelect();
var id = row.getData().id;
//var name = row.getData().pools;
//
duplicateArraySplice(id, _arrRowSelected_ID);
//duplicateArraySplice(name, _arrRowSelected_NAME);
},
renderComplete:function(){
//window.setTimeout(function(){
//$(".make-switch input").bootstrapSwitch();
//}, 1000);
},
});
}else{
$tgEl.find("i").removeClass("fa-minus-circle font-red").addClass("fa-plus-circle");
holderEl = $rowEl.find(".holderEl");
holderEl.slideUp();
_arrPrevTableEl[rowIdx].tabulator("destroy");
_arrPrevTableEl[rowIdx] = null;
}
}
// window.setInterval(function(){
// currentPageReload( $("#example-table") );
// }, 5000);
//////////////////////////////
}); //end. rdy
</script>
</body>
</html>
example.php
<?php $func = $_POST['func']; if( $func == "first_data" ){ //build data array $data = [ [id=>1, name=>"Billy Bob", progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>2, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>3, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>4, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>5, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], [id=>6, name=>"Billy Bob", progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>7, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>8, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>9, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>10, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], [id=>11, name=>"Billy Bob", progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>12, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>13, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>14, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>15, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], [id=>16, name=>"Billy Bob", progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>17, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>18, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>19, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>20, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], ]; }else if ( $func == "second_data" ){ $data = [ [id=>1, name=>"랜덤값으로 데이터확인".rand(1, 100), progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>2, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>3, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>4, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>5, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], [id=>6, name=>"Billy Bob", progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>7, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>8, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>9, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>10, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], [id=>11, name=>"Billy Bob".rand(1, 100), progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>12, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>13, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>14, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>15, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], [id=>16, name=>"Billy Bob", progress=>"12", gender=>"male", height=>1, col=>"red", dob=>"", driver=>1], [id=>17, name=>"Mary May", progress=>"1", gender=>"female", height=>2, col=>"blue", dob=>"14/05/1982", driver=>true], [id=>18, name=>"Christine Lobowski", progress=>"42", height=>0, col=>"green", dob=>"22/05/1982", driver=>"true"], [id=>19, name=>"Brendon Philips", progress=>"125", gender=>"male", height=>1, col=>"orange", dob=>"01/08/1980"], [id=>20, name=>"Margret Marmajuke", progress=>"16", gender=>"female", height=>5, col=>"yellow", dob=>"31/01/1999"], ]; } //return JSON formatted data echo(json_encode(["last_page"=>30, "data"=>$data]));
결과) 화면에서 + 를 누르면
결과) 아래와 같이 해당 내용이 출력된다.
'■ 프론트엔드 ■ > jQuery' 카테고리의 다른 글
ajaxSetup (0) | 2019.01.16 |
---|---|
tabulator 자주쓰는 고급옵션 (0) | 2018.12.18 |
img가 로드되고 난 이후에 w,h 반환받고 이미지 비율에 따른 계산하기 (0) | 2016.08.30 |
jquery context 라이브러리에서 메뉴 분기처리하여 보이고 추가하고 삭제하기.. (0) | 2016.08.25 |
자바스크립트 TypeError: (intermediate value)(intermediate value)(...) is not a function 에러 (2) | 2016.08.05 |