2021-04-22
Datatables를 ajax로 사용할때 serverSide옵션이 True로 되어 있으면, 서버에서 paging 및 search를 처리 할 수 있는 구문을 직접 짜야 한다.
예를 들어 서버의 데이터베이스에서 해당 자료를 가져 온다면,
POST로 넘어온 값들중 'start'와 'length' 값을 query문의 limit에 적용시켜 페이징을 구현해야 하고,
POST로 넘어온 값들중 'recordsFiltered'값에 전체 개수를 넘겨주어 개수 표시를 구현 해야하고,
POST로 넘어온 값들중 'search'값을 이용하여 where문에 모든 컬럼을 대상으로 검색을 구현해야 하고,
POST로 넘어온 값들중 'order'에 포함된 값을 바탕으로 order by를 구현 해야 한다.

하지만, 이렇게 구현할 경우, 보통 2가지 문제점이 발생한다.
1. pgaing에 포함될 범위만 client에서 뿌려주기 때문에, excel 다운로드시에 해당 부분만 다운 된다.
2. search가 keyup이벤트가 발생할때 마다 발생하기 때문에, 과도한 ajax로 서버에 부담을 주게 된다.

그래서 위 2가지 문제점을, 아래와 같이 수정 하면 된다.
1. excel 다운로드 시에 가져오는 자료를, 전체 자료를 대상으로 가져오게 한다.
2. search는 enter를 입력시에만 작동하게 한다.

아래는 해당 부분을 바꾸는 소스이다.
// excel 다운로드시에 전체가 client에서 보여주는 값 이외의 값들도 다운로드 되도록 하는 소스
var oldExportAction = function (self, e, dt, button, config) {
	if (button[0].className.indexOf('buttons-excel') >= 0) {
		if ($.fn.dataTable.ext.buttons.excelHtml5.available(dt, config)) {
			$.fn.dataTable.ext.buttons.excelHtml5.action.call(self, e, dt, button, config);
		}
		else {
			$.fn.dataTable.ext.buttons.excelFlash.action.call(self, e, dt, button, config);
		}
	} else if (button[0].className.indexOf('buttons-print') >= 0) {
		$.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
	}
};

var newExportAction = function (e, dt, button, config) {
	var self = this;
	var oldStart = dt.settings()[0]._iDisplayStart;

	dt.one('preXhr', function (e, s, data) {
		// Just this once, load all data from the server...
		data.start = 0;
		data.length = 2147483647;

		dt.one('preDraw', function (e, settings) {
			// Call the original action function
			oldExportAction(self, e, dt, button, config);

			dt.one('preXhr', function (e, s, data) {
				// DataTables thinks the first item displayed is index 0, but we're not drawing that.
				// Set the property to what it was before exporting.
				settings._iDisplayStart = oldStart;
				data.start = oldStart;
			});

			// Reload the grid with the original page. Otherwise,
			// API functions like table.cell(this) don't work properly.
			setTimeout(dt.ajax.reload, 0);

			// Prevent rendering of the full data to the DOM
			return false;
		});
	});

	// Requery the server with the new one-time export settings
	dt.ajax.reload();
};

var stack_1_list_dt = null
function stack_1_list(){

	var data_columns = [
		{title: "idx", name:'idx'},
		{title: "차수", name:'log_idx'},
		{title: "등록날짜", name:'r_date'},
		{title: "본부코드", name:'a1'},
		{title: "본부명", name:'a2'},

	];

	stack_1_list_dt = $('#stack_1_list_tbl1').DataTable({
		aLengthMenu: [[15, 100], [15, 100]]
		,columns: data_columns
		,order:[[0, 'asc']]
		,scrollY:'63vh'
		// ,scrollCollapse:true
		// ,paging:false
		,serverSide:true
		,ajax:{
			url: ajax_url
			,type: "POST"
			,data:function(data){
				// 서버에 POST로 값을 넘길때, 기본 값 이외의 값을 넘겨주는 부분
				data.mode = 100
				data.type = $('#select_list').val()
			}
			,dataSrc:function(data){
				var tmp2 = new Array();
				// console.log(data);
				i = 0;
				$.each( data.data, function(key, val){
					tmp2[i] = new Array();
					tmp2[i].push(i+1);
					tmp2[i].push(val.log_idx);
					tmp2[i].push(val.r_date);
					tmp2[i].push(val.head_code);
					tmp2[i].push(val.head_name);

					i++;
				});

				return tmp2;
			}
		}
		,processing:true
		,language:{
			"loadingRecords": " ",
			"processing": "데이터 불러오는 중..."
		}
		,columnDefs: [
			{visible: false, targets :[]},
			//{orderable: false, targets :[9]}
		]
		// ,dom: 'ilBfrt'
		,dom: 'lBfrtip'
		,buttons: [
			{
				extend: 'excel'
				,text: 'Excel'
				,filename: '엑셀출력_'+moment().format('YYYYMMDDhhmm')
				,title: ''
				,action: newExportAction // excel 다운로드시 전체를 보여주는 부분
			},
		]
		,autoWidth: true
		,scrollX: true
	});

	$('.buttons-excel').addClass('btn btn-dark btn-sm')

	// 검색시에 enter를 눌러야만 검색이 되도록 설정해주는 부분
	$('.dataTables_filter input').unbind();
	$('.dataTables_filter input').keyup(function (e) {
		if (e.keyCode == 13) /* if enter is pressed */ {
			stack_1_list_dt.search($(this).val()).draw();
		}
	});

}