fix orderable datatable on mutations and products index

This commit is contained in:
2025-06-16 19:01:11 +07:00
parent aa233eb793
commit b803068d0e
12 changed files with 383 additions and 178 deletions

View File

@@ -7,6 +7,15 @@ $(document).ready(function () {
return;
}
// Wait for DOM to be fully ready
setTimeout(function () {
initializeDataTable();
}, 100);
});
function initializeDataTable() {
console.log("Initializing DataTable...");
// Destroy existing table if any
if ($.fn.DataTable.isDataTable("#mutations-table")) {
$("#mutations-table").DataTable().destroy();
@@ -20,26 +29,24 @@ $(document).ready(function () {
ajax: {
url: $("#mutations-table").data("url"),
type: "GET",
data: function (d) {
console.log("DataTables request data:", d);
console.log("Order info:", d.order);
console.log("Columns info:", d.columns);
return d;
},
error: function (xhr, error, code) {
console.error("DataTables AJAX error:", error, code);
console.error("Response:", xhr.responseText);
},
},
columnDefs: [
{
targets: 0, // No. column
orderable: false,
searchable: false,
width: "5%",
},
{
targets: [1, 2, 3, 4, 5, 6, 7], // All sortable columns
orderable: true,
searchable: true,
},
{
targets: 8, // Action column
orderable: false,
searchable: false,
width: "20%",
className: "text-center",
},
@@ -52,43 +59,95 @@ $(document).ready(function () {
{
data: "DT_RowIndex",
name: "DT_RowIndex",
orderable: false,
searchable: false,
},
{
data: "mutation_number",
name: "mutation_number",
orderable: true,
},
{
data: "created_at",
name: "created_at",
orderable: true,
},
{
data: "from_dealer",
name: "fromDealer.name",
name: "from_dealer",
orderable: true,
},
{
data: "to_dealer",
name: "toDealer.name",
name: "to_dealer",
orderable: true,
},
{
data: "requested_by",
name: "requestedBy.name",
name: "requested_by",
orderable: true,
},
{
data: "total_items",
name: "total_items",
orderable: true,
},
{
data: "status",
name: "status",
orderable: true,
},
{
data: "action",
name: "action",
orderable: false,
searchable: false,
},
],
order: [[1, "desc"]], // Order by mutation_number desc (which follows ID order)
pageLength: 10,
responsive: true,
ordering: true, // Enable column ordering
orderMulti: false, // Single column ordering only
});
// Debug ordering events
table.on("order.dt", function () {
console.log("Order changed:", table.order());
});
// Add loading indicator for ordering
table.on("processing.dt", function (e, settings, processing) {
if (processing) {
console.log("DataTable processing started (ordering/filtering)");
} else {
console.log("DataTable processing finished");
}
});
// Manual click handler for column headers (fallback)
$("#mutations-table thead th").on("click", function () {
var columnIndex = $(this).index();
console.log("Column header clicked:", columnIndex, $(this).text());
// Skip if it's the first (No.) or last (Action) column
if (columnIndex === 0 || columnIndex === 8) {
console.log("Non-sortable column clicked, ignoring");
return;
}
// Check if DataTables is handling the click
if (
$(this).hasClass("sorting") ||
$(this).hasClass("sorting_asc") ||
$(this).hasClass("sorting_desc")
) {
console.log("DataTables should handle this click");
} else {
console.log("DataTables not handling click, manual trigger needed");
// Force DataTables to handle the ordering
table.order([columnIndex, "asc"]).draw();
}
});
// Handle Cancel Button Click with SweetAlert
@@ -117,43 +176,6 @@ $(document).ready(function () {
}
});
function cancelMutation(mutationId) {
$.ajax({
url: "/warehouse/mutations/" + mutationId + "/cancel",
type: "POST",
data: {
_token: $('meta[name="csrf-token"]').attr("content"),
},
success: function (response) {
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Berhasil!",
text: "Mutasi berhasil dibatalkan",
icon: "success",
timer: 2000,
showConfirmButton: false,
});
} else {
alert("Mutasi berhasil dibatalkan");
}
table.ajax.reload();
},
error: function (xhr) {
var errorMsg =
xhr.responseJSON?.message || "Gagal membatalkan mutasi";
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Error!",
text: errorMsg,
icon: "error",
});
} else {
alert("Error: " + errorMsg);
}
},
});
}
// Handle form submissions with loading state
$(document).on("submit", ".approve-form", function () {
$(this)
@@ -180,4 +202,43 @@ $(document).ready(function () {
$(this).siblings(".invalid-feedback").remove();
}
});
});
}
function cancelMutation(mutationId) {
$.ajax({
url: "/warehouse/mutations/" + mutationId + "/cancel",
type: "POST",
data: {
_token: $('meta[name="csrf-token"]').attr("content"),
},
success: function (response) {
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Berhasil!",
text: "Mutasi berhasil dibatalkan",
icon: "success",
timer: 2000,
showConfirmButton: false,
});
} else {
alert("Mutasi berhasil dibatalkan");
}
// Get table instance
var table = $("#mutations-table").DataTable();
table.ajax.reload();
},
error: function (xhr) {
var errorMsg =
xhr.responseJSON?.message || "Gagal membatalkan mutasi";
if (typeof Swal !== "undefined") {
Swal.fire({
title: "Error!",
text: errorMsg,
icon: "error",
});
} else {
alert("Error: " + errorMsg);
}
},
});
}

View File

@@ -1,68 +1,74 @@
$.ajaxSetup({
headers: {
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content"),
},
});
// Wait for DataTables to be available
function initializeDataTable() {
// Debug: Check if DataTables is loaded
console.log("DataTables available:", typeof $.fn.DataTable !== "undefined");
console.log("jQuery version:", $.fn.jquery);
$(document).ready(function () {
console.log("Products index.js loaded");
// Check if DataTables is available
if (typeof $.fn.DataTable === "undefined") {
console.error("DataTables is not loaded! Retrying in 1 second...");
setTimeout(initializeDataTable, 1000);
console.error("DataTables not available!");
return;
}
let tableContainer = $("#products-table");
let url = tableContainer.data("url");
// Wait for DOM to be fully ready
setTimeout(function () {
initializeDataTable();
}, 100);
});
console.log("Table URL:", url);
function initializeDataTable() {
console.log("Initializing DataTable...");
let table = $("#products-table").DataTable({
// Destroy existing table if any
if ($.fn.DataTable.isDataTable("#products-table")) {
$("#products-table").DataTable().destroy();
}
// Initialize DataTable
var table = $("#products-table").DataTable({
processing: true,
serverSide: true,
destroy: true,
ajax: {
url: url,
error: function (xhr, error, thrown) {
console.error("DataTables Ajax Error:", error, thrown);
url: $("#products-table").data("url"),
type: "GET",
data: function (d) {
console.log("DataTables request data:", d);
return d;
},
error: function (xhr, error, code) {
console.error("DataTables AJAX error:", error, code);
console.error("Response:", xhr.responseText);
},
},
order: [[0, "asc"]], // Order by first column (code) ascending
columns: [
{
data: "DT_RowIndex",
name: "DT_RowIndex",
orderable: false,
searchable: false,
},
{
data: "code",
name: "code",
orderable: true,
searchable: true,
},
{
data: "name",
name: "name",
orderable: true,
searchable: true,
},
{
data: "category_name",
name: "category.name",
name: "category_name",
orderable: true,
searchable: true,
},
{
data: "unit",
name: "unit",
orderable: true,
searchable: true,
},
{
data: "total_stock",
name: "total_stock",
orderable: false,
searchable: false,
},
{
data: "action",
@@ -71,53 +77,14 @@ function initializeDataTable() {
searchable: false,
},
],
columnDefs: [
{
targets: [4, 5], // total_stock and action columns
orderable: false,
},
],
initComplete: function (settings, json) {
console.log("DataTables initialized successfully");
console.log("Settings:", settings);
console.log(
"Column ordering enabled for:",
settings.aoColumns.map((col, index) => ({
index: index,
orderable: col.bSortable,
name: col.sName || col.mData,
}))
);
},
drawCallback: function (settings) {
console.log("DataTables draw completed");
},
headerCallback: function (thead, data, start, end, display) {
console.log("Header callback - sorting icons should be visible");
},
order: [[1, "asc"]], // Order by code asc
pageLength: 10,
responsive: true,
ordering: true,
orderMulti: false,
});
// Debug: Log table instance
console.log("DataTable instance:", table);
// Test column ordering programmatically
setTimeout(function () {
console.log("Testing column ordering...");
try {
table.order([1, "desc"]).draw();
console.log("Column ordering test successful");
} catch (e) {
console.error("Column ordering test failed:", e);
}
}, 2000);
}
// Initialize when document is ready
$(document).ready(function () {
console.log("Document ready, checking for DataTables...");
initializeDataTable();
});
$(document).on("click", ".btn-destroy-product", function () {
Swal.fire({
title: "Hapus produk?",
@@ -142,7 +109,14 @@ $(document).on("click", ".btn-destroy-product", function () {
"Produk berhasil dihapus.",
"success"
);
$("#products-table").DataTable().ajax.reload();
try {
if ($.fn.DataTable.isDataTable("#products-table")) {
$("#products-table").DataTable().ajax.reload();
}
} catch (e) {
console.error("Error reloading table:", e);
location.reload(); // Fallback to page reload
}
},
error: function (xhr) {
Swal.fire("Error!", "Gagal menghapus produk.", "error");
@@ -174,9 +148,16 @@ $(document).on("click", ".btn-toggle-active", function () {
},
success: function (response) {
if (response.success) {
$("#products-table")
.DataTable()
.ajax.reload(null, false);
try {
if ($.fn.DataTable.isDataTable("#products-table")) {
$("#products-table")
.DataTable()
.ajax.reload(null, false);
}
} catch (e) {
console.error("Error reloading table:", e);
location.reload(); // Fallback to page reload
}
Swal.fire("Berhasil!", response.message, "success");
}
},
@@ -197,9 +178,25 @@ $(document).on("click", ".btn-product-stock-dealers", function () {
const productName = $(this).data("name");
const ajaxUrl = $(this).data("url");
// Check if modal elements exist
if ($("#product-name-title").length === 0) {
console.error("Modal title element not found");
return;
}
if ($("#dealer-stock-table").length === 0) {
console.error("Dealer stock table element not found");
return;
}
// Set product name in modal title
$("#product-name-title").text(productName);
// Destroy existing DataTable if any
if ($.fn.DataTable.isDataTable("#dealer-stock-table")) {
$("#dealer-stock-table").DataTable().destroy();
}
// Initialize or reload DataTable inside modal
$("#dealer-stock-table").DataTable({
destroy: true,
@@ -210,6 +207,14 @@ $(document).on("click", ".btn-product-stock-dealers", function () {
data: {
product_id: productId,
},
error: function (xhr, error, thrown) {
console.error(
"Dealer stock DataTables Ajax Error:",
error,
thrown
);
console.error("Response:", xhr.responseText);
},
},
columns: [
{
@@ -226,7 +231,15 @@ $(document).on("click", ".btn-product-stock-dealers", function () {
},
],
initComplete: function () {
$("#dealerStockModal").modal("show");
try {
if ($("#dealerStockModal").length > 0) {
$("#dealerStockModal").modal("show");
} else {
console.error("Modal #dealerStockModal not found");
}
} catch (e) {
console.error("Error showing modal:", e);
}
},
});
});

View File

@@ -50,6 +50,24 @@
@section('styles')
<style>
/* Override any conflicting styles */
#mutations-table thead th {
position: relative !important;
cursor: pointer !important;
user-select: none !important;
}
#mutations-table thead th:not(.sorting_disabled) {
cursor: pointer !important;
}
/* Ensure DataTables classes are applied */
#mutations-table.dataTable thead th.sorting,
#mutations-table.dataTable thead th.sorting_asc,
#mutations-table.dataTable thead th.sorting_desc {
cursor: pointer !important;
background-image: none !important;
}
/* DataTables Sorting Icons */
table.dataTable thead .sorting:before,
table.dataTable thead .sorting:after,
@@ -92,7 +110,25 @@ table.dataTable thead th {
table.dataTable thead th.sorting,
table.dataTable thead th.sorting_asc,
table.dataTable thead th.sorting_desc {
cursor: pointer;
cursor: pointer !important;
pointer-events: auto !important;
}
/* Force clickable area */
table.dataTable thead th.sorting:hover,
table.dataTable thead th.sorting_asc:hover,
table.dataTable thead th.sorting_desc:hover {
background-color: #f8f9fa;
}
/* Ensure sorting icons are visible */
table.dataTable thead .sorting:before,
table.dataTable thead .sorting_asc:before,
table.dataTable thead .sorting_desc:before {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
}
</style>
@endsection

View File

@@ -2,28 +2,69 @@
@section('styles')
<style>
/* Ensure DataTables sorting icons are visible */
/* DataTables Sorting Icons - Make them visible and clear */
table.dataTable thead .sorting:before,
table.dataTable thead .sorting:after,
table.dataTable thead .sorting_asc:before,
table.dataTable thead .sorting_asc:after,
table.dataTable thead .sorting_desc:before,
table.dataTable thead .sorting_desc:after {
opacity: 0.5 !important;
font-family: 'Font Awesome 5 Free';
font-weight: 900;
opacity: 0.6;
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
}
table.dataTable thead .sorting_asc:before,
/* Sorting icons */
table.dataTable thead .sorting:before {
content: "\f0dc"; /* fa-sort */
opacity: 0.4;
}
table.dataTable thead .sorting_asc:before {
content: "\f0de"; /* fa-sort-up */
opacity: 1;
color: #007bff;
}
table.dataTable thead .sorting_desc:before {
content: "\f0dd"; /* fa-sort-down */
opacity: 1;
color: #007bff;
}
/* Hide default after pseudo elements */
table.dataTable thead .sorting:after,
table.dataTable thead .sorting_asc:after,
table.dataTable thead .sorting_desc:after {
opacity: 1 !important;
display: none;
}
/* Make sure table headers are clickable */
table.dataTable thead th {
cursor: pointer;
position: relative;
padding-right: 30px !important; /* Space for sorting icon */
}
table.dataTable thead th.sorting_disabled {
cursor: default;
padding-right: 8px !important;
}
/* Hover effect for sortable columns */
table.dataTable thead th.sorting:hover,
table.dataTable thead th.sorting_asc:hover,
table.dataTable thead th.sorting_desc:hover {
background-color: #f8f9fa;
}
/* Ensure sorting icons are visible on hover */
table.dataTable thead th.sorting:hover:before {
opacity: 0.8;
}
</style>
@@ -57,6 +98,7 @@ table.dataTable thead th.sorting_disabled {
<table class="table table-striped table-bordered table-hover" id="products-table" data-url="{{ route("products.index") }}">
<thead>
<tr>
<th>No.</th>
<th>Kode</th>
<th>Nama</th>
<th>Kategori</th>
@@ -65,6 +107,8 @@ table.dataTable thead th.sorting_disabled {
<th>Aksi</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<!--end: Datatable -->
</div>