I’m using DataTables to manage a table where certain contents are in collapsible <tr>
elements. Initially, these <tr>
are hidden (display: none), and they only become visible when their corresponding button (Details
) is pressed .
When using the DataTables search filter, I’d like the table to display the main row that contains the matching content that is in the hidden <tr>
element, without requiring the user to click the “Details
” button first.
Here is my current setup:
Each collapsible row has a unique ID, and I store the content of each row in a dictionary with the following structure:
{ ‘id_of_row’: [‘content1’, ‘content2’, ‘content3’, …] }
The goal is to search within the dictionary when the user types in the search box, and if a match is found in any of the dictionary elements, it uses the id_of_row and the corresponding main row with that id should be displayed.
Example Problem:
If I search for the term ‘requ’, nothing shows up because the corresponding content is inside a collapsed <tr>
. However, if I manually expand the <tr>
by clicking the “Details” button and make that content visible and if there is a match inside that content it will show up.
What I’ve Tried:
I use a dictionary that maps the main row’s ID to an array of content for that row. When the search input matches an element in the dictionary, I want the corresponding main row to be displayed, even if it’s content its inside a currently hidden element.
However, I can’t seem to get this to work as expected. The row is not being displayed when its content matches the search term unless it’s manually expanded.
Here is a simplified version of my current code:
@using Newtonsoft.Json
@{
// Sample machine names
var MachineNames = new List<string> { "Machine A", "Machine B", "Machine C" };
// Sample requests using anonymous objects
var requests = new[]
{
new { Id = 1, ContactName = "Client A", CompanyName = "Machine A", Status = "Pending", Msg = "Request 1" },
new { Id = 2, ContactName = "Client B", CompanyName = "Machine B", Status = "In Progress", Msg = "Request 2" },
new { Id = 3, ContactName = "Client C", CompanyName = "Machine C", Status = "Completed", Msg = "Request 3" }
};
// Sample dictionary data for matching the behavior of your original example
var requestDictionary = new Dictionary<int, string[]>
{
{ 1, new[] { "client a", "machine a", "pending", "request 1" } },
{ 2, new[] { "client b", "machine b", "in progress", "request 2" } },
{ 3, new[] { "client c", "machine c", "completed", "request 3" } }
};
}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Collapsible Table with Custom Filter</title>
<!-- Include jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Include DataTables CSS & JS -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css">
<script src="https://cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"></script>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
.show {
display: table-row;
}
.dataTables_filter label {
font-weight: bold;
font-size: 1.2em;
}
.dataTables_filter input {
margin-left: 10px;
padding: 5px;
border-radius: 5px;
border: 1px solid #ccc;
}
#search-container {
width: auto;
padding: 5px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<h1>Collapsible Table with Custom Search Filter</h1>
<!-- Search filter -->
<div id="search-container"></div>
<!-- The table with collapsible rows -->
<table id="myTable" class="display table-flexible">
<thead>
<tr>
<th>Request ID</th>
<th>Client</th>
<th>Machine</th>
<th>Status</th>
<th>Description</th>
</tr>
</thead>
<tbody>
@foreach (var request in requests)
{
<tr>
<td>@request.Id</td>
<td>@request.ContactName</td>
<td data-id="@request.CompanyName">@request.CompanyName</td>
<td>@request.Status</td>
<td>
<button class="btn btn-info btn-sm toggle-btn" data-target="#[email protected]">Details</button>
</td>
</tr>
<tr id="[email protected]" class="details-row" style="display: none;">
<td colspan="6">
<div class="card custom-card-body details-card">
<div class="detail-item">
<strong>Message:</strong>
<p class="tw-font-bold">@request.Msg</p>
</div>
</div>
</td>
</tr>
}
</tbody>
</table>
@section Scripts {
<script src="https://cdn.datatables.net/1.10.5/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
var requestDictionary = @Html.Raw(JsonConvert.SerializeObject(requestDictionary));
console.log(requestDictionary); // Debugging purposes
// Initialize DataTable
var table = $('#myTable').DataTable({
columnDefs: [{
"defaultContent": "-",
"targets": "_all"
}],
paging: false,
ordering: false,
info: false,
dom: 'ft'
});
// Move search box to custom container
$('#search-container').html($('.dataTables_filter'));
// Custom search functionality using the requestDictionary
function filterTable(searchTerm) {
var rows = table.rows().nodes(); // Fetch all rows
$(rows).each(function () {
var $row = $(this); // The `tr` element
// Extract requestId from the first column (adjust if necessary)
var requestId = $row.find('td').first().text().trim();
// Ensure requestId is a valid number
requestId = parseInt(requestId, 10);
if (isNaN(requestId)) {
return; // Skip rows without a valid requestId
}
// Check if requestId exists in the dictionary
if (!requestDictionary.hasOwnProperty(requestId)) {
return;
}
var requestDetails = requestDictionary[requestId];
console.log(requestDetails); // Debugging purposes
// Check if any of the details contain the search term
var match = requestDetails.some(function (detail) {
return detail.toLowerCase().includes(searchTerm.toLowerCase());
});
// Show or hide the row based on the search match
if (match) {
console.log("HIT - Showing row for requestId:", requestId);
$row.css("display", "table-row"); // Set display to table-row
} else {
console.log("MISS - Hiding row for requestId:", requestId);
$row.css("display", "none"); // Hide row
}
});
}
// Handle search input
$('.dataTables_filter input[type="search"]').on('input', function () {
var searchTerm = $(this).val().trim();
filterTable(searchTerm);
});
// Attach event listeners for toggling rows
$('.toggle-btn').on('click', function () {
var target = $(this).data('target');
$(target).fadeToggle(500);
});
});
</script>
}
</body>
Thank you for your time and attention!