Я создаю веб-страницу для хобби, используя Bootstrap 5.3.3 и JS DataTables 2.0.5. На странице у меня есть таблица с данными некоторых игроков. В таблице я сделал так, что при нажатии на некоторые ячейки отображается всплывающее окно с дополнительной информацией. Есть все необходимые модули, и всплывающее окно работает нормально, когда таблица отображается во всю ширину. Однако, если я настрою размер экрана так, чтобы некоторые столбцы свернулись, всплывающее окно для этих столбцов не будет отображаться.
Пример воспроизведения в JS Fiddle:
<head>
<meta charset = "utf-8">
<title>Responsive Table Popover</title>
<meta name = "description" content = "">
<meta name = "author" content = "">
<meta name = "viewport" content = "width=device-width,initial-scale=1">
<link href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel = "stylesheet" integrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin = "anonymous">
<link href = "https://cdn.datatables.net/2.0.5/css/dataTables.bootstrap5.min.css" rel = "stylesheet">
<link href = "https://cdn.datatables.net/responsive/3.0.2/css/responsive.bootstrap5.min.css" rel = "stylesheet">
</head>
<body>
<div class = "container">
<table id = "players-data" class = "table table-striped" style = "font-size:13px; width: 100%;">
<thead style = "white-space: nowrap;">
<tr>
<th>Player</th>
<th>Details 1</th>
<th>Details 2</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script src = "https://code.jquery.com/jquery-3.7.1.min.js" integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous"> </script>
<script charset = "utf8" src = "https://cdn.datatables.net/2.0.5/js/dataTables.min.js"></script>
<script charset = "utf8" src = "https://cdn.datatables.net/2.0.5/js/dataTables.bootstrap5.min.js"></script>
<script charset = "utf8" src = "https://cdn.datatables.net/responsive/3.0.2/js/dataTables.responsive.min.js"></script>
<script charset = "utf8" src = "https://cdn.datatables.net/responsive/3.0.2/js/responsive.bootstrap5.min.js"></script>
<script src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity = "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin = "anonymous"></script>
<script type = "text/javascript">
let players = [
{player: 'Best', details_1: 'Cool', details_2: 'Sharp', details_1_extra: 'Extra Cool', details_2_extra: 'Extra Sharp'},
{player: 'Worst', details_1: 'Hot', details_2: 'Slow', details_1_extra: 'Extra Hot', details_2_extra: 'Extra Slow'}
];
$('#players-data').DataTable({
data: players,
columns: [
{data: 'player', render: DataTable.render.text(), sortable: true},
{data: 'details_1', sortable: false, class: "text-center", render: function (data, type, row) {
if (data)
{
return `<a
tabindex = "0"
type = "button"
class = "btn btn-link btn-sm"
data-bs-container = "body"
data-bs-trigger = "focus"
data-bs-toggle = "popover"
data-bs-placement = "bottom"
data-bs-html = "true"
data-bs-custom-class = "custom-popover"
data-bs-content = "${row.details_1_extra}">
${data}
</a>`;
} else {
return data;
}
}},
{data: 'details_2', sortable: false, class: "text-center", render: function (data, type, row) {
if (data)
{
return `<a
tabindex = "0"
type = "button"
class = "btn btn-link btn-sm"
data-bs-container = "body"
data-bs-trigger = "focus"
data-bs-toggle = "popover"
data-bs-placement = "bottom"
data-bs-html = "true"
data-bs-custom-class = "custom-popover"
data-bs-content = "${row.details_2_extra}">
${data}
</a>`;
} else {
return data;
}
}}
],
destroy: true,
searching: false,
paging: true,
info: false,
ordering: true,
stateSave: true,
responsive: true,
drawCallback: function (settings) {
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle = "popover"]');
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl));
}
});
</script>
</body>
Когда таблица имеет полную ширину (показаны все столбцы), всплывающие окна в обоих столбцах работают нормально:
Когда столбец «Подробности 2» свернут из-за размера экрана, всплывающее окно больше не отображается в нем, независимо от того, нажимаете ли вы на текст ячейки:
Чего мне не хватает в моем коде, чтобы всплывающие окна работали несмотря ни на что?
Вы должны сделать элемент таблицы дочерним элементом элемента div, который имеет класс «table-Response», например:
<div class = "table-responsive">
<table id = "players-data" class = "table table-striped" style = "font-size:13px; width: 100%;">
<thead style = "white-space: nowrap;">
<tr>
<th>Player</th>
<th>Details 1</th>
<th>Details 2</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
Попробуйте инициализировать всплывающие окна с помощью «$(document).ready(function() { })» перед их использованием.
$(document).ready(function() {const popoverTriggerList = document.querySelectorAll('[data-bs-toggle = "popover"]'); const popoverList = [...popoverTriggerList].map(popoverTriggerEl => новый бутстрап .Popover(popoverTriggerEl) });
нет, они должны быть инициализированы в drawCallback, поскольку они создаются динамически в столбцах DataTable. Не помогает в любом случае.
Когда размер datatable изменяется и при развертывании свернутых ячеек, datatable фактически добавляет еще одну строку, которая содержит свернутые ячейки, но в элементе ul/li/span, т. е. создает новые элементы DOM, к которым не подключено всплывающее окно или какой-либо другой прослушиватель.
пример вновь добавленных элементов:
<tr data-dt-row = "1" class = "child">
<td class = "child" colspan = "1">
<ul data-dtr-index = "1" class = "dtr-details">
<li class = " text-center" data-dtr-index = "1" data-dt-row = "1" data-dt-column = "1">
<span class = "dtr-title">Details 1</span> <span class = "dtr-data"><a tabindex = "0" type = "button" class = "btn btn-link btn-sm" data-bs-container = "body" data-bs-trigger = "focus" data-bs-toggle = "popover" data-bs-placement = "bottom" data-bs-html = "true" data-bs-custom-class = "custom-popover" data-bs-content = "Extra Hot">
Hot
</a></span></li>
<li class = " text-center" data-dtr-index = "2" data-dt-row = "1" data-dt-column = "2"><span class = "dtr-title">Details 2</span> <span class = "dtr-data"><a tabindex = "0" type = "button" class = "btn btn-link btn-sm" data-bs-container = "body" data-bs-trigger = "focus" data-bs-toggle = "popover" data-bs-placement = "bottom" data-bs-html = "true" data-bs-custom-class = "custom-popover" data-bs-content = "Extra Slow">
Slow
</a></span></li>
</ul>
</td>
</tr>
Итак, что вам нужно сделать, так это при развертывании скрытых ячеек, то есть когда datatable добавляет эти элементы, найти и инициировать всплывающее окно для этих вновь добавленных элементов.
Это можно сделать, добавив отдельный прослушиватель ко всей таблице или, точнее, к сворачивающемуся элементу, который имеет класс .dtr-control
, а затем найдите вновь добавленную строку (которая является следующим родственным элементом родительского элемента управления с классом .child
) и найдите в ней все недавно добавленные всплывающие окна и инициируйте их:
$('#players-data').on('click', 'td.dtr-control', function (evt) {
const popovers = $(this).parent().next('.child').find('[data-bs-toggle = "popover"]')
.each((i,el)=>new bootstrap.Popover(el));
});
демо:
<head>
<meta charset = "utf-8">
<title>Responsive Table Popover</title>
<meta name = "description" content = "">
<meta name = "author" content = "">
<meta name = "viewport" content = "width=device-width,initial-scale=1">
<link href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel = "stylesheet" integrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin = "anonymous">
<link href = "https://cdn.datatables.net/2.0.5/css/dataTables.bootstrap5.min.css" rel = "stylesheet">
<link href = "https://cdn.datatables.net/responsive/3.0.2/css/responsive.bootstrap5.min.css" rel = "stylesheet">
</head>
<body>
<div class = "container">
<table id = "players-data" class = "table table-striped" style = "font-size:13px; width: 100%;">
<thead style = "white-space: nowrap;">
<tr>
<th>Player</th>
<th>Details 1</th>
<th>Details 2</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<script src = "https://code.jquery.com/jquery-3.7.1.min.js" integrity = "sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo = " crossorigin = "anonymous">
</script>
<script charset = "utf8" src = "https://cdn.datatables.net/2.0.5/js/dataTables.min.js"></script>
<script charset = "utf8" src = "https://cdn.datatables.net/2.0.5/js/dataTables.bootstrap5.min.js"></script>
<script charset = "utf8" src = "https://cdn.datatables.net/responsive/3.0.2/js/dataTables.responsive.min.js"></script>
<script charset = "utf8" src = "https://cdn.datatables.net/responsive/3.0.2/js/responsive.bootstrap5.min.js"></script>
<script src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity = "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin = "anonymous"></script>
<script type = "text/javascript">
let players = [{
player: 'Best',
details_1: 'Cool',
details_2: 'Sharp',
details_1_extra: 'Extra Cool',
details_2_extra: 'Extra Sharp'
},
{
player: 'Worst',
details_1: 'Hot',
details_2: 'Slow',
details_1_extra: 'Extra Hot',
details_2_extra: 'Extra Slow'
}
];
$('#players-data').DataTable({
data: players,
columns: [{
data: 'player',
render: DataTable.render.text(),
sortable: true
},
{
data: 'details_1',
sortable: false,
class: "text-center",
render: function(data, type, row) {
if (data) {
return `<a
tabindex = "0"
type = "button"
class = "btn btn-link btn-sm"
data-bs-container = "body"
data-bs-trigger = "focus"
data-bs-toggle = "popover"
data-bs-placement = "bottom"
data-bs-html = "true"
data-bs-custom-class = "custom-popover"
data-bs-content = "${row.details_1_extra}">
${data}
</a>`;
} else {
return data;
}
}
},
{
data: 'details_2',
sortable: false,
class: "text-center",
render: function(data, type, row) {
if (data) {
return `<a
tabindex = "0"
type = "button"
class = "btn btn-link btn-sm"
data-bs-container = "body"
data-bs-trigger = "focus"
data-bs-toggle = "popover"
data-bs-placement = "bottom"
data-bs-html = "true"
data-bs-custom-class = "custom-popover"
data-bs-content = "${row.details_2_extra}">
${data}
</a>`;
} else {
return data;
}
}
}
],
destroy: true,
searching: false,
paging: true,
info: false,
ordering: true,
stateSave: true,
responsive: true,
drawCallback: function(settings) {
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle = "popover"]');
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl));
}
});
$('#players-data').on('click', 'td.dtr-control', function(evt) {
const popovers = $(this).parent().next('.child').find('[data-bs-toggle = "popover"]')
.each((i, el) => new bootstrap.Popover(el));
});
</script>
</body>
Круто, работает, спасибо! Есть ли где-нибудь в документах DataTable это можно увидеть или это личный опыт?
ну, нужно покопаться в коде. вариант реагирования описан здесь: datatables.net/reference/option, но я не уверен, что какой-либо вариант охватывает ваш случай, а также, похоже, явно не упоминается, что он добавляет новые элементы в DOM, что приводит к любые слушатели, которые будут удалены, включая экземпляр popover
все еще не работает, я попробовал это в JS Fiddle