/** * DataTables Basic */ 'use strict'; let fv, offCanvasEl; document.addEventListener('DOMContentLoaded', function (e) { (function () { const formAddNewRecord = document.getElementById('form-add-new-record'); setTimeout(() => { const newRecord = document.querySelector('.create-new'), offCanvasElement = document.querySelector('#add-new-record'); // To open offCanvas, to add new record if (newRecord) { newRecord.addEventListener('click', function () { offCanvasEl = new bootstrap.Offcanvas(offCanvasElement); // Empty fields on offCanvas open ((offCanvasElement.querySelector('.dt-full-name').value = ''), (offCanvasElement.querySelector('.dt-post').value = ''), (offCanvasElement.querySelector('.dt-email').value = ''), (offCanvasElement.querySelector('.dt-date').value = ''), (offCanvasElement.querySelector('.dt-salary').value = '')); // Open offCanvas with form offCanvasEl.show(); }); } }, 200); // Form validation for Add new record fv = FormValidation.formValidation(formAddNewRecord, { fields: { basicFullname: { validators: { notEmpty: { message: 'The name is required' } } }, basicPost: { validators: { notEmpty: { message: 'Post field is required' } } }, basicEmail: { validators: { notEmpty: { message: 'The Email is required' }, emailAddress: { message: 'The value is not a valid email address' } } }, basicDate: { validators: { notEmpty: { message: 'Joining Date is required' }, date: { format: 'MM/DD/YYYY', message: 'The value is not a valid date' } } }, basicSalary: { validators: { notEmpty: { message: 'Basic Salary is required' } } } }, plugins: { trigger: new FormValidation.plugins.Trigger(), bootstrap5: new FormValidation.plugins.Bootstrap5({ // Use this for enabling/changing valid/invalid class // eleInvalidClass: '', eleValidClass: '', rowSelector: '.form-control-validation' }), submitButton: new FormValidation.plugins.SubmitButton(), // defaultSubmit: new FormValidation.plugins.DefaultSubmit(), autoFocus: new FormValidation.plugins.AutoFocus() }, init: instance => { instance.on('plugins.message.placed', function (e) { if (e.element.parentElement.classList.contains('input-group')) { e.element.parentElement.insertAdjacentElement('afterend', e.messageElement); } }); } }); // FlatPickr Initialization & Validation const flatpickrDate = document.querySelector('[name="basicDate"]'); if (flatpickrDate) { flatpickrDate.flatpickr({ enableTime: false, monthSelectorType: 'static', static: true, // See https://flatpickr.js.org/formatting/ dateFormat: 'm/d/Y', // After selecting a date, we need to revalidate the field onChange: function () { fv.revalidateField('basicDate'); } }); } })(); // init function const dt_basic_table = document.querySelector('.datatables-basic'); let dt_basic; if (dt_basic_table) { let tableTitle = document.createElement('h5'); tableTitle.classList.add('card-title', 'mb-0', 'text-md-start', 'text-center', 'pb-md-0', 'pb-6'); tableTitle.innerHTML = 'DataTable with Buttons'; dt_basic = new DataTable(dt_basic_table, { ajax: assetsPath + 'json/table-datatable.json', columns: [ { data: 'id' }, { data: 'id', orderable: false, render: DataTable.render.select() }, { data: 'id' }, { data: 'full_name' }, { data: 'email' }, { data: 'start_date' }, { data: 'salary' }, { data: 'status' }, { data: 'id' } ], columnDefs: [ { // For Responsive className: 'control', orderable: false, searchable: false, responsivePriority: 2, targets: 0, render: function (data, type, full, meta) { return ''; } }, { // For Checkboxes targets: 1, orderable: false, searchable: false, responsivePriority: 3, checkboxes: true, render: function () { return ''; }, checkboxes: { selectAllRender: '' } }, { targets: 2, searchable: false, visible: false }, { // Avatar image/badge, Name and post targets: 3, responsivePriority: 4, render: function (data, type, full, meta) { const userImg = full['avatar']; const name = full['full_name']; const post = full['post']; let output; if (userImg) { // For Avatar image output = `Avatar`; } else { // For Avatar badge const stateNum = Math.floor(Math.random() * 6); const states = ['success', 'danger', 'warning', 'info', 'dark', 'primary', 'secondary']; const state = states[stateNum]; let initials = name.match(/\b\w/g) || []; initials = ((initials.shift() || '') + (initials.pop() || '')).toUpperCase(); output = `${initials}`; } // Creates full output for row const rowOutput = `
${output}
${name} ${post}
`; return rowOutput; } }, { responsivePriority: 1, targets: 4 }, { // Label targets: -2, render: function (data, type, full, meta) { const statusNumber = full.status; const statuses = { 1: { title: 'Current', class: 'bg-label-primary' }, 2: { title: 'Professional', class: 'bg-label-success' }, 3: { title: 'Rejected', class: 'bg-label-danger' }, 4: { title: 'Resigned', class: 'bg-label-warning' }, 5: { title: 'Applied', class: 'bg-label-info' } }; if (typeof statuses[statusNumber] === 'undefined') { return data; } return ` ${statuses[statusNumber].title} `; } }, { // Actions targets: -1, title: 'Actions', orderable: false, searchable: false, render: function (data, type, full, meta) { return ( '
' + '' + '' + '
' + '' ); } } ], select: { style: 'multi', selector: 'td:nth-child(2)' }, order: [[2, 'desc']], layout: { top2Start: { rowClass: 'row card-header flex-column flex-md-row border-bottom mx-0 px-3', features: [tableTitle] }, top2End: { features: [ { buttons: [ { extend: 'collection', className: 'btn btn-label-primary dropdown-toggle me-4', text: ' Export', buttons: [ { extend: 'print', text: `Print`, exportOptions: { columns: [3, 4, 5, 6, 7], format: { body: function (inner, coldex, rowdex) { if (inner.length <= 0) return inner; // Check if inner is HTML content if (inner.indexOf('<') > -1) { const parser = new DOMParser(); const doc = parser.parseFromString(inner, 'text/html'); // Get all text content let text = ''; // Handle specific elements const userNameElements = doc.querySelectorAll('.user-name'); if (userNameElements.length > 0) { userNameElements.forEach(el => { // Get text from nested structure const nameText = el.querySelector('.fw-medium')?.textContent || el.querySelector('.d-block')?.textContent || el.textContent; text += nameText.trim() + ' '; }); } else { // Get regular text content text = doc.body.textContent || doc.body.innerText; } return text.trim(); } return inner; } } }, customize: function (win) { win.document.body.style.color = config.colors.headingColor; win.document.body.style.borderColor = config.colors.borderColor; win.document.body.style.backgroundColor = config.colors.bodyBg; const table = win.document.body.querySelector('table'); table.classList.add('compact'); table.style.color = 'inherit'; table.style.borderColor = 'inherit'; table.style.backgroundColor = 'inherit'; } }, { extend: 'csv', text: `Csv`, exportOptions: { columns: [3, 4, 5, 6, 7], format: { body: function (inner, coldex, rowdex) { if (inner.length <= 0) return inner; // Parse HTML content const parser = new DOMParser(); const doc = parser.parseFromString(inner, 'text/html'); let text = ''; // Handle user-name elements specifically const userNameElements = doc.querySelectorAll('.user-name'); if (userNameElements.length > 0) { userNameElements.forEach(el => { // Get text from nested structure - try different selectors const nameText = el.querySelector('.fw-medium')?.textContent || el.querySelector('.d-block')?.textContent || el.textContent; text += nameText.trim() + ' '; }); } else { // Handle other elements (status, role, etc) text = doc.body.textContent || doc.body.innerText; } return text.trim(); } } } }, { extend: 'excel', text: `Excel`, exportOptions: { columns: [3, 4, 5, 6, 7], format: { body: function (inner, coldex, rowdex) { if (inner.length <= 0) return inner; // Parse HTML content const parser = new DOMParser(); const doc = parser.parseFromString(inner, 'text/html'); let text = ''; // Handle user-name elements specifically const userNameElements = doc.querySelectorAll('.user-name'); if (userNameElements.length > 0) { userNameElements.forEach(el => { // Get text from nested structure - try different selectors const nameText = el.querySelector('.fw-medium')?.textContent || el.querySelector('.d-block')?.textContent || el.textContent; text += nameText.trim() + ' '; }); } else { // Handle other elements (status, role, etc) text = doc.body.textContent || doc.body.innerText; } return text.trim(); } } } }, { extend: 'pdf', text: `Pdf`, exportOptions: { columns: [3, 4, 5, 6, 7], format: { body: function (inner, coldex, rowdex) { if (inner.length <= 0) return inner; // Parse HTML content const parser = new DOMParser(); const doc = parser.parseFromString(inner, 'text/html'); let text = ''; // Handle user-name elements specifically const userNameElements = doc.querySelectorAll('.user-name'); if (userNameElements.length > 0) { userNameElements.forEach(el => { // Get text from nested structure - try different selectors const nameText = el.querySelector('.fw-medium')?.textContent || el.querySelector('.d-block')?.textContent || el.textContent; text += nameText.trim() + ' '; }); } else { // Handle other elements (status, role, etc) text = doc.body.textContent || doc.body.innerText; } return text.trim(); } } } }, { extend: 'copy', text: `Copy`, exportOptions: { columns: [3, 4, 5, 6, 7], format: { body: function (inner, coldex, rowdex) { if (inner.length <= 0) return inner; // Parse HTML content const parser = new DOMParser(); const doc = parser.parseFromString(inner, 'text/html'); let text = ''; // Handle user-name elements specifically const userNameElements = doc.querySelectorAll('.user-name'); if (userNameElements.length > 0) { userNameElements.forEach(el => { // Get text from nested structure - try different selectors const nameText = el.querySelector('.fw-medium')?.textContent || el.querySelector('.d-block')?.textContent || el.textContent; text += nameText.trim() + ' '; }); } else { // Handle other elements (status, role, etc) text = doc.body.textContent || doc.body.innerText; } return text.trim(); } } } } ] }, { text: ' Add New Record', className: 'create-new btn btn-primary' } ] } ] }, topStart: { rowClass: 'row mx-0 px-3 my-0 justify-content-between border-bottom', features: [ { pageLength: { menu: [10, 25, 50, 100], text: 'Show_MENU_entries' } } ] }, topEnd: { search: { placeholder: '' } }, bottomStart: { rowClass: 'row mx-3 justify-content-between', features: ['info'] }, bottomEnd: 'paging' }, language: { paginate: { next: '', previous: '', first: '', last: '' } }, responsive: { details: { display: DataTable.Responsive.display.modal({ header: function (row) { const data = row.data(); return 'Details of ' + data['full_name']; } }), type: 'column', renderer: function (api, rowIdx, columns) { const data = columns .map(function (col) { return col.title !== '' // Do not show row in modal popup if title is blank (for check box) ? ` ${col.title}: ${col.data} ` : ''; }) .join(''); if (data) { const div = document.createElement('div'); div.classList.add('table-responsive'); const table = document.createElement('table'); div.appendChild(table); table.classList.add('table'); table.classList.add('datatables-basic'); const tbody = document.createElement('tbody'); tbody.innerHTML = data; table.appendChild(tbody); return div; } return false; } } } }); // Add New record // ? Remove/Update this code as per your requirements var count = 101; // On form submit, if form is valid fv.on('core.form.valid', function () { let new_name = document.querySelector('.add-new-record .dt-full-name').value, new_post = document.querySelector('.add-new-record .dt-post').value, new_email = document.querySelector('.add-new-record .dt-email').value, new_date = document.querySelector('.add-new-record .dt-date').value, new_salary = document.querySelector('.add-new-record .dt-salary').value; if (new_name != '') { dt_basic.row .add({ id: count, full_name: new_name, post: new_post, email: new_email, start_date: new_date, salary: '$' + new_salary, status: 5 }) .draw(); count++; // Hide offcanvas using javascript method offCanvasEl.hide(); } }); //? The 'delete-record' class is necessary for the functionality of the following code. document.addEventListener('click', function (e) { if (e.target.classList.contains('delete-record')) { dt_basic.row(e.target.closest('tr')).remove().draw(); const modalEl = document.querySelector('.dtr-bs-modal'); if (modalEl && modalEl.classList.contains('show')) { const modal = bootstrap.Modal.getInstance(modalEl); modal?.hide(); } } }); } // Complex Header DataTable const dt_complex_header_table = document.querySelector('.dt-complex-header'); let dt_complex; if (dt_complex_header_table) { dt_complex = new DataTable(dt_complex_header_table, { ajax: assetsPath + 'json/table-datatable.json', columns: [ { data: 'full_name' }, { data: 'email' }, { data: 'city' }, { data: 'post' }, { data: 'salary' }, { data: 'status' }, { data: '' } ], columnDefs: [ { // Label targets: -2, render: function (data, type, full, meta) { const statusNumber = full.status; const statuses = { 1: { title: 'Current', class: 'bg-label-primary' }, 2: { title: 'Professional', class: 'bg-label-success' }, 3: { title: 'Rejected', class: 'bg-label-danger' }, 4: { title: 'Resigned', class: 'bg-label-warning' }, 5: { title: 'Applied', class: 'bg-label-info' } }; if (typeof statuses[statusNumber] === 'undefined') { return data; } return ` ${statuses[statusNumber].title} `; } }, { // Actions targets: -1, title: 'Actions', orderable: false, searchable: false, render: function (data, type, full, meta) { return ( '
' + '' + '' + '
' + '' ); } } ], order: [[2, 'desc']], layout: { topStart: { rowClass: 'row mx-3 my-0 justify-content-between', features: [ { pageLength: { menu: [7, 10, 25, 50, 100], text: 'Show_MENU_entries' } } ] }, topEnd: { search: { placeholder: '' } }, bottomStart: { rowClass: 'row mx-3 justify-content-between', features: ['info'] }, bottomEnd: 'paging' }, displayLength: 7, language: { paginate: { next: '', previous: '', first: '', last: '' } } }); //? The 'delete-record' class is necessary for the functionality of the following code. document.addEventListener('click', function (e) { if (e.target.classList.contains('delete-record')) { dt_complex.row(e.target.closest('tr')).remove().draw(); const modalEl = document.querySelector('.dtr-bs-modal'); if (modalEl && modalEl.classList.contains('show')) { const modal = bootstrap.Modal.getInstance(modalEl); modal?.hide(); } } }); } // Row Grouping DataTable const dt_row_grouping_table = document.querySelector('.dt-row-grouping'); let dt_row_grouping, groupColumn = 2; if (dt_row_grouping_table) { dt_row_grouping = new DataTable(dt_row_grouping_table, { ajax: assetsPath + 'json/table-datatable.json', columns: [ { data: 'id' }, { data: 'full_name' }, { data: 'post' }, { data: 'email' }, { data: 'city' }, { data: 'start_date' }, { data: 'salary' }, { data: 'status' }, { data: '' } ], columnDefs: [ { // For Responsive className: 'control', orderable: false, targets: 0, searchable: false, render: function (data, type, full, meta) { return ''; } }, { visible: false, targets: groupColumn }, { // Label targets: -2, render: function (data, type, full, meta) { const statusNumber = full.status; const statuses = { 1: { title: 'Current', class: 'bg-label-primary' }, 2: { title: 'Professional', class: 'bg-label-success' }, 3: { title: 'Rejected', class: 'bg-label-danger' }, 4: { title: 'Resigned', class: 'bg-label-warning' }, 5: { title: 'Applied', class: 'bg-label-info' } }; if (typeof statuses[statusNumber] === 'undefined') { return data; } return ` ${statuses[statusNumber].title} `; } }, { // Actions targets: -1, title: 'Actions', orderable: false, searchable: false, className: 'd-flex align-items-center', render: function (data, type, full, meta) { return ( '
' + '' + '' + '
' + '' ); } } ], layout: { topStart: { rowClass: 'row mx-3 my-0 justify-content-between', features: [ { pageLength: { menu: [7, 10, 25, 50, 100], text: 'Show_MENU_entries' } } ] }, topEnd: { search: { placeholder: '' } }, bottomStart: { rowClass: 'row mx-3 justify-content-between', features: ['info'] }, bottomEnd: 'paging' }, order: [[groupColumn, 'asc']], displayLength: 7, language: { paginate: { next: '', previous: '', first: '', last: '' } }, drawCallback: function (settings) { const api = this.api(); const rows = api.rows({ page: 'current' }).nodes(); let last = null; api .column(groupColumn, { page: 'current' }) .data() .each(function (group, i) { if (last !== group) { const newRow = document.createElement('tr'); newRow.classList.add('group'); const newCell = document.createElement('td'); newCell.setAttribute('colspan', '8'); newCell.textContent = group; newRow.appendChild(newCell); rows[i].parentNode.insertBefore(newRow, rows[i]); last = group; } }); }, responsive: { details: { display: DataTable.Responsive.display.modal({ header: function (row) { var data = row.data(); return 'Details of ' + data['full_name']; } }), type: 'column', renderer: function (api, rowIdx, columns) { const data = columns .map(function (col) { return col.title !== '' // Do not show row in modal popup if title is blank (for check box) ? ` ${col.title}: ${col.data} ` : ''; }) .join(''); if (data) { const div = document.createElement('div'); div.classList.add('table-responsive'); const table = document.createElement('table'); div.appendChild(table); table.classList.add('table'); const tbody = document.createElement('tbody'); tbody.innerHTML = data; table.appendChild(tbody); return div; } return false; } } } }); //? The 'delete-record' class is necessary for the functionality of the following code. document.addEventListener('click', function (e) { if (e.target.classList.contains('delete-record')) { dt_row_grouping.row(e.target.closest('tr')).remove().draw(); const modalEl = document.querySelector('.dtr-bs-modal'); if (modalEl && modalEl.classList.contains('show')) { const modal = bootstrap.Modal.getInstance(modalEl); modal?.hide(); } } }); } // Multilingual DataTable const dt_multilingual_table = document.querySelector('.dt-multilingual'); let dt_multilingual, lang = 'DE'; if (dt_multilingual_table) { dt_multilingual = new DataTable(dt_multilingual_table, { ajax: assetsPath + 'json/table-datatable.json', columns: [ { data: 'id' }, { data: 'full_name' }, { data: 'post' }, { data: 'email' }, { data: 'start_date' }, { data: 'salary' }, { data: 'status' }, { data: '' } ], columnDefs: [ { // For Responsive className: 'control', orderable: false, targets: 0, searchable: false, render: function (data, type, full, meta) { return ''; } }, { // Label targets: -2, render: function (data, type, full, meta) { const statusNumber = full.status; const statuses = { 1: { title: 'Current', class: 'bg-label-primary' }, 2: { title: 'Professional', class: 'bg-label-success' }, 3: { title: 'Rejected', class: 'bg-label-danger' }, 4: { title: 'Resigned', class: 'bg-label-warning' }, 5: { title: 'Applied', class: 'bg-label-info' } }; if (typeof statuses[statusNumber] === 'undefined') { return data; } return ` ${statuses[statusNumber].title} `; } }, { // Actions targets: -1, title: 'Actions', orderable: false, className: '', searchable: false, render: function (data, type, full, meta) { return ( '
' + '
' + '' + '' + '
' + '' + '
' ); } } ], language: { url: 'https://cdn.datatables.net/plug-ins/1.11.5/i18n/de-' + lang + '.json', paginate: { first: '', last: '', next: '', previous: '' } }, order: [[2, 'desc']], displayLength: 7, layout: { topStart: { rowClass: 'row m-3 my-0 justify-content-between', features: [ { pageLength: { menu: [7, 10, 25, 50, 100] } } ] }, topEnd: { search: { placeholder: 'Geben Sie hier die Suche ein' } }, bottomStart: { rowClass: 'row mx-3 justify-content-between', features: ['info'] }, bottomEnd: 'paging' }, responsive: { details: { display: DataTable.Responsive.display.modal({ header: function (row) { var data = row.data(); return 'Details of ' + data['full_name']; } }), type: 'column', renderer: function (api, rowIdx, columns) { const data = columns .map(function (col) { return col.title !== '' // Do not show row in modal popup if title is blank (for check box) ? ` ${col.title}: ${col.data} ` : ''; }) .join(''); if (data) { const div = document.createElement('div'); div.classList.add('table-responsive'); const table = document.createElement('table'); div.appendChild(table); table.classList.add('table'); const tbody = document.createElement('tbody'); tbody.innerHTML = data; table.appendChild(tbody); return div; } return false; } } } }); //? The 'delete-record' class is necessary for the functionality of the following code. document.addEventListener('click', function (e) { if (e.target.classList.contains('delete-record')) { dt_multilingual.row(e.target.closest('tr')).remove().draw(); const modalEl = document.querySelector('.dtr-bs-modal'); if (modalEl && modalEl.classList.contains('show')) { const modal = bootstrap.Modal.getInstance(modalEl); modal?.hide(); } } }); } // Filter form control to default size // ? setTimeout used for multilingual table initialization setTimeout(() => { const elementsToModify = [ { selector: '.dt-buttons .btn', classToRemove: 'btn-secondary' }, { selector: '.dt-search .form-control', classToRemove: 'form-control-sm', classToAdd: 'ms-4' }, { selector: '.dt-length .form-select', classToRemove: 'form-select-sm' }, { selector: '.dt-layout-table', classToRemove: 'row mt-2' }, { selector: '.dt-layout-end', classToAdd: 'mt-0' }, { selector: '.dt-layout-end .dt-search', classToAdd: 'mt-0 mt-md-6 mb-6' }, { selector: '.dt-layout-start', classToAdd: 'mt-0' }, { selector: '.dt-layout-end .dt-buttons', classToAdd: 'mb-0' }, { selector: '.dt-layout-full', classToRemove: 'col-md col-12', classToAdd: 'table-responsive' } ]; // Delete record elementsToModify.forEach(({ selector, classToRemove, classToAdd }) => { document.querySelectorAll(selector).forEach(element => { if (classToRemove) { classToRemove.split(' ').forEach(className => element.classList.remove(className)); } if (classToAdd) { classToAdd.split(' ').forEach(className => element.classList.add(className)); } }); }); }, 100); });