Added data-bulk to the ajax modal to allow for bulk GET collection of selected ids that have a class of bulk-select, converted expense and client bulk modals to use the the new ajax-modal

This commit is contained in:
johnnyq
2025-11-06 11:26:08 -05:00
parent 293a2b800e
commit 0cf1e338c2
20 changed files with 985 additions and 773 deletions

View File

@@ -1,66 +1,74 @@
// Ajax Modal Load Script
//
/* Example Triggering -->
<button type="button"
class="btn btn-primary ajax-modal" // Triggers the AJAX Modal
data-modal-size = "lg" // Optional: Defaults to md
data-modal-url="modals/contact/contact_edit.php?id=id">
Edit Contact
</button>
*/
$(document).on('click', '.ajax-modal', function (e) {
e.preventDefault();
e.preventDefault();
const $trigger = $(this);
const modalUrl = $trigger.data('modal-url');
const modalSize = $trigger.data('modal-size') || 'md';
const modalId = 'ajaxModal_' + new Date().getTime();
const $trigger = $(this);
let modalUrl = $trigger.data('modal-url');
const modalSize = $trigger.data('modal-size') || 'md';
const modalId = 'ajaxModal_' + new Date().getTime();
// Show loading spinner while fetching content
const loadingSpinner = `
<div id="modal-loading-spinner" class="text-center p-5">
<i class="fas fa-spinner fa-spin fa-2x text-muted"></i>
// -------- Optional bulk mode (activated via data-bulk="true") --------
if ($trigger.data('bulk') === true || $trigger.data('bulk') === 'true') {
const selector = $trigger.data('bulk-selector') || '.bulk-select:checked';
const param = $trigger.data('bulk-param') || 'selected_ids[]';
const ids = Array.from(document.querySelectorAll(selector)).map(cb => cb.value);
if (!ids.length) {
alert('Please select at least one item.');
return; // abort opening modal
}
// Merge ids into existing query string safely
const urlObj = new URL(modalUrl, window.location.href);
ids.forEach(id => urlObj.searchParams.append(param, id));
// Preserve path + updated query (avoid absolute origin for relative AJAX)
modalUrl = urlObj.pathname + (urlObj.search ? '?' + urlObj.searchParams.toString() : '');
}
// --------------------------------------------------------------------
// Show loading spinner while fetching content
const loadingSpinner = `
<div id="modal-loading-spinner" class="text-center p-5">
<i class="fas fa-spinner fa-spin fa-2x text-muted"></i>
</div>`;
$('.content-wrapper').append(loadingSpinner);
// Make AJAX request
$.ajax({
url: modalUrl,
method: 'GET',
dataType: 'json',
success: function (response) {
$('#modal-loading-spinner').remove();
if (response.error) {
alert(response.error);
return;
}
const modalHtml = `
<div class="modal fade" id="${modalId}" tabindex="-1">
<div class="modal-dialog modal-${modalSize}">
<div class="modal-content border-dark">
${response.content}
</div>
</div>
</div>`;
$('.content-wrapper').append(loadingSpinner);
// Make AJAX request
$.ajax({
url: modalUrl,
method: 'GET',
dataType: 'json',
success: function (response) {
$('#modal-loading-spinner').remove();
$('.content-wrapper').append(modalHtml);
const $modal = $('#' + modalId);
$modal.modal('show');
if (response.error) {
alert(response.error);
return;
}
// Build modal wrapper
const modalHtml = `
<div class="modal fade" id="${modalId}" tabindex="-1">
<div class="modal-dialog modal-${modalSize}">
<div class="modal-content border-dark">
${response.content}
</div>
</div>
</div>`;
$('.content-wrapper').append(modalHtml);
const $modal = $('#' + modalId);
$modal.modal('show');
// Remove modal after it's closed
$modal.on('hidden.bs.modal', function () {
$(this).remove();
});
},
error: function (xhr, status, error) {
$('#modal-loading-spinner').remove();
alert('Error loading modal content. Please try again.');
console.error('Modal AJAX Error:', status, error);
}
});
});
$modal.on('hidden.bs.modal', function () {
$(this).remove();
});
},
error: function (xhr, status, error) {
$('#modal-loading-spinner').remove();
alert('Error loading modal content. Please try again.');
console.error('Modal AJAX Error:', status, error);
}
});
});

View File

@@ -1,40 +1,54 @@
// Allow selecting and editing multiple records at once
// bulk_actions.js
// Allow selecting and editing multiple records at once (no <form> dependency)
var form = document.getElementById("bulkActions"); // Get the form element by its id
var checkboxes = form.querySelectorAll('input[type="checkbox"].bulk-select'); // Select only checkboxes with class "bulk-select"
var selectedCount = document.getElementById("selectedCount");
var selectAllCheckbox = document.getElementById("selectAllCheckbox"); // The "select all" checkbox
// Event listener for each checkbox
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].addEventListener("click", updateSelectedCount);
// --- Helpers ---
function getCheckboxes() {
// Always query fresh in case rows are re-rendered
return Array.from(document.querySelectorAll('input[type="checkbox"].bulk-select'));
}
function getSelectedIds() {
return getCheckboxes()
.filter(cb => cb.checked)
.map(cb => cb.value);
}
// Function to update the count of selected checkboxes
function updateSelectedCount() {
var count = 0;
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
count++;
const count = getSelectedIds().length;
const selectedCountEl = document.getElementById('selectedCount');
if (selectedCountEl) {
selectedCountEl.textContent = count;
}
}
selectedCount.textContent = count; // Display the count
// Show or hide the multi-action button
document.getElementById("bulkActionButton").hidden = count === 0;
const bulkBtn = document.getElementById('bulkActionButton');
if (bulkBtn) {
bulkBtn.hidden = count === 0;
}
}
// Function to check/uncheck all checkboxes
// --- Select All Handling ---
function checkAll(source) {
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = source.checked;
}
updateSelectedCount(); // Update the count after changing checkbox states
getCheckboxes().forEach(cb => {
cb.checked = source.checked;
});
updateSelectedCount();
}
// Event listener for the "select all" checkbox
// Wire select-all checkbox if present
const selectAllCheckbox = document.getElementById('selectAllCheckbox');
if (selectAllCheckbox) {
selectAllCheckbox.addEventListener("click", function() {
checkAll(this);
});
selectAllCheckbox.addEventListener('click', function () {
checkAll(this);
});
}
// --- Per-row Checkbox Handling ---
// Use event delegation so it still works if table rows are re-rendered
document.addEventListener('click', function (e) {
const cb = e.target.closest('input[type="checkbox"].bulk-select');
if (!cb) return;
updateSelectedCount();
});
// --- Initialize count on page load ---
document.addEventListener('DOMContentLoaded', updateSelectedCount);