Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tables-datatables-advanced.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. /**
  2. * DataTables Advanced (js)
  3. */
  4. 'use strict';
  5. document.addEventListener('DOMContentLoaded', function (e) {
  6. const startDateEle = document.querySelector('.start_date');
  7. const endDateEle = document.querySelector('.end_date');
  8. // Advanced Search Functions Starts
  9. // --------------------------------------------------------------------
  10. // Datepicker for advanced filter
  11. const rangePickr = document.querySelector('.flatpickr-range'),
  12. dateFormat = 'MM/DD/YYYY';
  13. if (rangePickr) {
  14. rangePickr.flatpickr({
  15. mode: 'range',
  16. dateFormat: 'm/d/Y',
  17. orientation: isRtl ? 'auto right' : 'auto left',
  18. locale: {
  19. format: dateFormat
  20. },
  21. onClose: function (selectedDates, dateStr, instance) {
  22. let startDate = '';
  23. let endDate = new Date();
  24. if (selectedDates[0] !== undefined) {
  25. startDate = new Date(selectedDates[0]).toLocaleDateString('en-US', {
  26. month: '2-digit',
  27. day: '2-digit',
  28. year: 'numeric'
  29. });
  30. startDateEle.value = startDate; // Using `.value` to update input fields in vanilla JS
  31. }
  32. if (selectedDates[1] !== undefined) {
  33. endDate = new Date(selectedDates[1]).toLocaleDateString('en-US', {
  34. month: '2-digit',
  35. day: '2-digit',
  36. year: 'numeric'
  37. });
  38. endDateEle.value = endDate; // Using `.value` to update input fields in vanilla JS
  39. }
  40. // Trigger custom events without jQuery
  41. rangePickr.dispatchEvent(new Event('change'));
  42. rangePickr.dispatchEvent(new Event('keyup'));
  43. }
  44. });
  45. }
  46. // Advance filter function
  47. // We pass the column location, the start date, and the end date
  48. // Clear existing custom filters
  49. if (typeof $.fn !== 'undefined' && typeof $.fn.dataTableExt !== 'undefined') {
  50. $.fn.dataTableExt.afnFiltering.length = 0;
  51. }
  52. const filterByDate = function (column, startDate, endDate) {
  53. // Custom filter syntax requires pushing the new filter to the global filter array
  54. if (typeof $.fn !== 'undefined' && typeof $.fn.dataTableExt !== 'undefined') {
  55. $.fn.dataTableExt.afnFiltering.push(function (oSettings, aData, iDataIndex) {
  56. const rowDate = normalizeDate(aData[column]);
  57. const start = normalizeDate(startDate);
  58. const end = normalizeDate(endDate);
  59. // If our date from the row is between the start and end
  60. if (start <= rowDate && rowDate <= end) {
  61. return true;
  62. } else if (rowDate >= start && end === '' && start !== '') {
  63. return true;
  64. } else if (rowDate <= end && start === '' && end !== '') {
  65. return true;
  66. } else {
  67. return false;
  68. }
  69. });
  70. }
  71. };
  72. // Convert date strings to a Date object, then normalize into YYYYMMDD format
  73. const normalizeDate = function (dateString) {
  74. const date = new Date(dateString);
  75. const normalized =
  76. date.getFullYear() +
  77. ('0' + (date.getMonth() + 1)).slice(-2) + // Ensure month is two digits
  78. ('0' + date.getDate()).slice(-2); // Ensure day is two digits
  79. return normalized;
  80. };
  81. // Advanced Search Functions Ends
  82. // Ajax Sourced Server-side
  83. // --------------------------------------------------------------------
  84. const dt_ajax_table = document.querySelector('.datatables-ajax');
  85. if (dt_ajax_table) {
  86. let dt_ajax = new DataTable(dt_ajax_table, {
  87. processing: true,
  88. ajax: {
  89. url: assetsPath + 'json/ajax.php',
  90. dataSrc: 'data'
  91. },
  92. layout: {
  93. topStart: {
  94. rowClass: 'row mx-3 my-0 justify-content-between',
  95. features: [
  96. {
  97. pageLength: {
  98. menu: [7, 10, 25, 50, 100],
  99. text: 'Show_MENU_entries'
  100. }
  101. }
  102. ]
  103. },
  104. topEnd: {
  105. search: {
  106. placeholder: ''
  107. }
  108. },
  109. bottomStart: {
  110. rowClass: 'row mx-3 justify-content-between',
  111. features: ['info']
  112. },
  113. bottomEnd: 'paging'
  114. },
  115. language: {
  116. paginate: {
  117. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  118. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  119. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  120. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  121. }
  122. }
  123. });
  124. }
  125. // Column Search
  126. // --------------------------------------------------------------------
  127. const dt_filter_table = document.querySelector('.dt-column-search');
  128. if (dt_filter_table) {
  129. // Setup - add a text input to each footer cell
  130. const thead = document.querySelector('.dt-column-search thead');
  131. // Clone the first row and append it as the second row
  132. const cloneRow = thead.querySelector('tr').cloneNode(true);
  133. thead.appendChild(cloneRow);
  134. // Select the newly added second row (the cloned one)
  135. const secondRowCells = thead.querySelectorAll('tr:nth-child(2) th');
  136. secondRowCells.forEach((th, i) => {
  137. const title = th.textContent;
  138. const input = document.createElement('input');
  139. input.type = 'text';
  140. input.className = 'form-control';
  141. input.placeholder = `Search ${title}`;
  142. // Add left and right border styles to the parent element
  143. th.style.borderLeft = 'none';
  144. if (i === secondRowCells.length - 1) {
  145. th.style.borderRight = 'none';
  146. }
  147. th.innerHTML = '';
  148. th.appendChild(input);
  149. // Event listener for search functionality
  150. input.addEventListener('keyup', function () {
  151. if (dt_filter.column(i).search() !== this.value) {
  152. dt_filter.column(i).search(this.value).draw();
  153. }
  154. });
  155. input.addEventListener('change', function () {
  156. if (dt_filter.column(i).search() !== this.value) {
  157. dt_filter.column(i).search(this.value).draw();
  158. }
  159. });
  160. });
  161. let dt_filter = new DataTable(dt_filter_table, {
  162. ajax: assetsPath + 'json/table-datatable.json',
  163. columns: [
  164. { data: 'full_name' },
  165. { data: 'email' },
  166. { data: 'post' },
  167. { data: 'city' },
  168. { data: 'start_date' },
  169. { data: 'salary' }
  170. ],
  171. orderCellsTop: true,
  172. layout: {
  173. topStart: {
  174. rowClass: 'row mx-3 my-0 justify-content-between',
  175. features: [
  176. {
  177. pageLength: {
  178. menu: [7, 10, 25, 50, 100],
  179. text: 'Show_MENU_entries'
  180. }
  181. }
  182. ]
  183. },
  184. topEnd: {
  185. search: {
  186. placeholder: 'Type search here'
  187. }
  188. },
  189. bottomStart: {
  190. rowClass: 'row mx-3 justify-content-between',
  191. features: ['info']
  192. },
  193. bottomEnd: 'paging'
  194. },
  195. language: {
  196. paginate: {
  197. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  198. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  199. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  200. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  201. }
  202. }
  203. });
  204. }
  205. // Advanced Search
  206. // --------------------------------------------------------------------
  207. const dt_adv_filter_table = document.querySelector('.dt-advanced-search');
  208. let dt_adv_filter;
  209. // Advanced Filter table
  210. if (dt_adv_filter_table) {
  211. dt_adv_filter = new DataTable(dt_adv_filter_table, {
  212. ajax: assetsPath + 'json/table-datatable.json',
  213. columns: [
  214. { data: '' },
  215. { data: 'full_name' },
  216. { data: 'email' },
  217. { data: 'post' },
  218. { data: 'city' },
  219. { data: 'start_date' },
  220. { data: 'salary' }
  221. ],
  222. columnDefs: [
  223. {
  224. className: 'control',
  225. orderable: false,
  226. targets: 0,
  227. render: function (data, type, full, meta) {
  228. return '';
  229. }
  230. }
  231. ],
  232. layout: {
  233. topStart: {
  234. rowClass: 'm-0',
  235. features: []
  236. },
  237. topEnd: {},
  238. bottomStart: {
  239. rowClass: 'row mx-3 justify-content-between',
  240. features: ['info']
  241. },
  242. bottomEnd: 'paging'
  243. },
  244. language: {
  245. paginate: {
  246. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  247. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  248. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  249. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  250. }
  251. },
  252. orderCellsTop: true,
  253. responsive: {
  254. details: {
  255. display: DataTable.Responsive.display.modal({
  256. header: function (row) {
  257. var data = row.data();
  258. return 'Details of ' + data['full_name'];
  259. }
  260. }),
  261. type: 'column',
  262. renderer: function (api, rowIdx, columns) {
  263. const data = columns
  264. .map(function (col) {
  265. return col.title !== '' // Do not show row in modal popup if title is blank (for check box)
  266. ? `<tr data-dt-row="${col.rowIndex}" data-dt-column="${col.columnIndex}">
  267. <td>${col.title}:</td>
  268. <td>${col.data}</td>
  269. </tr>`
  270. : '';
  271. })
  272. .join('');
  273. if (data) {
  274. const div = document.createElement('div');
  275. div.classList.add('table-responsive');
  276. const table = document.createElement('table');
  277. div.appendChild(table);
  278. table.classList.add('table');
  279. const tbody = document.createElement('tbody');
  280. tbody.innerHTML = data;
  281. table.appendChild(tbody);
  282. return div;
  283. }
  284. return false;
  285. }
  286. }
  287. }
  288. });
  289. }
  290. // on keyup from input field
  291. document.querySelectorAll('input.dt-input').forEach(input => {
  292. input.addEventListener('keyup', function () {
  293. const column = this.getAttribute('data-column');
  294. const value = this.value;
  295. filterColumn(column, value);
  296. });
  297. });
  298. // Filter column wise function
  299. function filterColumn(i, val) {
  300. if (i == 5) {
  301. const startDate = startDateEle.value;
  302. const endDate = endDateEle.value;
  303. if (startDate !== '' && endDate !== '') {
  304. // Reset custom filter
  305. $.fn.dataTable.ext.search.length = 0;
  306. // Custom date filtering logic
  307. filterByDate(i, startDate, endDate);
  308. }
  309. // Redraw the DataTable
  310. dt_adv_filter.draw();
  311. } else {
  312. // Search the column using the DataTable instance
  313. dt_adv_filter
  314. .column(i) // Access the correct column
  315. .search(val, false, true) // Apply the search
  316. .draw(); // Redraw the table
  317. }
  318. }
  319. // Responsive Table
  320. // --------------------------------------------------------------------
  321. const dt_responsive_table = document.querySelector('.dt-responsive');
  322. if (dt_responsive_table) {
  323. let dt_responsive = new DataTable(dt_responsive_table, {
  324. ajax: assetsPath + 'json/table-datatable.json',
  325. columns: [
  326. { data: 'id' },
  327. { data: 'full_name' },
  328. { data: 'email' },
  329. { data: 'post' },
  330. { data: 'city' },
  331. { data: 'start_date' },
  332. { data: 'salary' },
  333. { data: 'age' },
  334. { data: 'experience' },
  335. { data: 'status' }
  336. ],
  337. columnDefs: [
  338. {
  339. className: 'control',
  340. orderable: false,
  341. targets: 0,
  342. searchable: false,
  343. render: function (data, type, full, meta) {
  344. return '';
  345. }
  346. },
  347. {
  348. // Label
  349. targets: -1,
  350. render: function (data, type, full, meta) {
  351. const statusNumber = full.status;
  352. const statuses = {
  353. 1: { title: 'Current', class: 'bg-label-primary' },
  354. 2: { title: 'Professional', class: 'bg-label-success' },
  355. 3: { title: 'Rejected', class: 'bg-label-danger' },
  356. 4: { title: 'Resigned', class: 'bg-label-warning' },
  357. 5: { title: 'Applied', class: 'bg-label-info' }
  358. };
  359. if (typeof statuses[statusNumber] === 'undefined') {
  360. return data;
  361. }
  362. return `
  363. <span class="badge ${statuses[statusNumber].class}">
  364. ${statuses[statusNumber].title}
  365. </span>
  366. `;
  367. }
  368. }
  369. ],
  370. destroy: true,
  371. layout: {
  372. topStart: {
  373. rowClass: 'row mx-3 my-0 justify-content-between',
  374. features: [
  375. {
  376. pageLength: {
  377. menu: [7, 10, 25, 50, 100],
  378. text: 'Show_MENU_entries'
  379. }
  380. }
  381. ]
  382. },
  383. topEnd: {
  384. search: {
  385. placeholder: ''
  386. }
  387. },
  388. bottomStart: {
  389. rowClass: 'row mx-3 justify-content-between',
  390. features: ['info']
  391. },
  392. bottomEnd: 'paging'
  393. },
  394. language: {
  395. paginate: {
  396. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  397. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  398. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  399. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  400. }
  401. },
  402. responsive: {
  403. details: {
  404. display: DataTable.Responsive.display.modal({
  405. header: function (row) {
  406. var data = row.data();
  407. return 'Details of ' + data['full_name'];
  408. }
  409. }),
  410. type: 'column',
  411. renderer: function (api, rowIdx, columns) {
  412. const data = columns
  413. .map(function (col) {
  414. return col.title !== '' // Do not show row in modal popup if title is blank (for check box)
  415. ? `<tr data-dt-row="${col.rowIndex}" data-dt-column="${col.columnIndex}">
  416. <td>${col.title}:</td>
  417. <td>${col.data}</td>
  418. </tr>`
  419. : '';
  420. })
  421. .join('');
  422. if (data) {
  423. const div = document.createElement('div');
  424. div.classList.add('table-responsive');
  425. const table = document.createElement('table');
  426. div.appendChild(table);
  427. table.classList.add('table');
  428. const tbody = document.createElement('tbody');
  429. tbody.innerHTML = data;
  430. table.appendChild(tbody);
  431. return div;
  432. }
  433. return false;
  434. }
  435. }
  436. }
  437. });
  438. }
  439. // Responsive with Child Rows
  440. // --------------------------------------------------------------------
  441. const dt_responsive_child_table = document.querySelector('.dt-responsive-child');
  442. let dt_responsive_child;
  443. if (dt_responsive_child_table) {
  444. dt_responsive_child = new DataTable(dt_responsive_child_table, {
  445. ajax: assetsPath + 'json/table-datatable.json',
  446. columns: [
  447. { data: null },
  448. { data: 'full_name' },
  449. { data: 'email' },
  450. { data: 'city' },
  451. { data: 'start_date' },
  452. { data: 'age' },
  453. { data: 'status' }
  454. ],
  455. columnDefs: [
  456. {
  457. className: 'dt-control',
  458. orderable: false,
  459. targets: 0,
  460. searchable: false,
  461. defaultContent: ''
  462. },
  463. {
  464. // Label
  465. targets: -1,
  466. render: function (data, type, full, meta) {
  467. const statusNumber = full.status;
  468. const statuses = {
  469. 1: { title: 'Current', class: 'bg-label-primary' },
  470. 2: { title: 'Professional', class: 'bg-label-success' },
  471. 3: { title: 'Rejected', class: 'bg-label-danger' },
  472. 4: { title: 'Resigned', class: 'bg-label-warning' },
  473. 5: { title: 'Applied', class: 'bg-label-info' }
  474. };
  475. if (typeof statuses[statusNumber] === 'undefined') {
  476. return data;
  477. }
  478. return `
  479. <span class="badge ${statuses[statusNumber].class}">
  480. ${statuses[statusNumber].title}
  481. </span>
  482. `;
  483. }
  484. }
  485. ],
  486. layout: {
  487. topStart: {
  488. rowClass: 'row mx-3 my-0 justify-content-between',
  489. features: [
  490. {
  491. pageLength: {
  492. menu: [7, 10, 25, 50, 100],
  493. text: 'Show_MENU_entries'
  494. }
  495. }
  496. ]
  497. },
  498. topEnd: {
  499. search: {
  500. placeholder: ''
  501. }
  502. },
  503. bottomStart: {
  504. rowClass: 'row mx-3 justify-content-between',
  505. features: ['info']
  506. },
  507. bottomEnd: 'paging'
  508. },
  509. scrollX: true,
  510. language: {
  511. paginate: {
  512. next: '<i class="icon-base bx bx-chevron-right scaleX-n1-rtl icon-18px"></i>',
  513. previous: '<i class="icon-base bx bx-chevron-left scaleX-n1-rtl icon-18px"></i>',
  514. first: '<i class="icon-base bx bx-chevrons-left scaleX-n1-rtl icon-18px"></i>',
  515. last: '<i class="icon-base bx bx-chevrons-right scaleX-n1-rtl icon-18px"></i>'
  516. }
  517. }
  518. });
  519. }
  520. // Formatting function for row details - modify as you need
  521. function format(d) {
  522. // `d` is the original data object for the row
  523. return (
  524. '<dl>' +
  525. '<dt>Full name:</dt>' +
  526. '<dd>' +
  527. d.full_name +
  528. '</dd>' +
  529. '<dt>Post:</dt>' +
  530. '<dd>' +
  531. d.post +
  532. '</dd>' +
  533. '<dt>Salary:</dt>' +
  534. '<dd>' +
  535. d.salary +
  536. '</dd>' +
  537. '<dt>Experience:</dt>' +
  538. '<dd>' +
  539. d.experience +
  540. '</dd>' +
  541. '</dl>'
  542. );
  543. }
  544. // Add event listener for opening and closing details
  545. dt_responsive_child.on('click', 'td.dt-control', function (e) {
  546. let tr = e.target.closest('tr');
  547. let row = dt_responsive_child.row(tr);
  548. if (row.child.isShown()) {
  549. // This row is already open - close it
  550. row.child.hide();
  551. } else {
  552. // Open this row
  553. row.child(format(row.data())).show();
  554. }
  555. });
  556. // Filter form control to default size
  557. // ? setTimeout used for multilingual table initialization
  558. setTimeout(() => {
  559. const elementsToModify = [
  560. { selector: '.dt-buttons .btn', classToRemove: 'btn-secondary' },
  561. { selector: '.dt-search .form-control', classToRemove: 'form-control-sm', classToAdd: 'ms-4' },
  562. { selector: '.dt-length .form-select', classToRemove: 'form-select-sm' },
  563. { selector: '.dt-layout-table', classToRemove: 'row mt-2' },
  564. { selector: '.dt-layout-end', classToAdd: 'mt-0' },
  565. { selector: '.dt-layout-end .dt-search', classToAdd: 'mt-md-6 mt-0' },
  566. { selector: '.dt-layout-full', classToRemove: 'col-md col-12', classToAdd: 'table-responsive' }
  567. ];
  568. // Delete record
  569. elementsToModify.forEach(({ selector, classToRemove, classToAdd }) => {
  570. document.querySelectorAll(selector).forEach(element => {
  571. if (classToRemove) {
  572. classToRemove.split(' ').forEach(className => element.classList.remove(className));
  573. }
  574. if (classToAdd) {
  575. classToAdd.split(' ').forEach(className => element.classList.add(className));
  576. }
  577. });
  578. });
  579. }, 100);
  580. });