Buongiorno come da titolo, vorrei esporvi il mio problema, e magari qualcuno potrà darmi una mano.
ho una tabella del tipo Parent/Child, dove la tabella padre mi restituisce corretamente i risultati dei dipendenti, li ho creato il paginatore che funziona bene, restituisce 5 record per pagina e la casella di ricerca, funziona bene anch'essa, la tabella figlio mi restituisce tutti i badge relativi al dipendente selezionato attraverso il click su icona awesome, quindi la tabella figlio si espande e e mostra tutti i badge relativi al dipendente, nel file php che estrapola i dati da query e li passa all'ajax c'è una funzione che mi fa il conteggio dei badge e mi scorpora i badge rilasciati come ex novo e quelli rilasciati come duplicati che il dipendente ha avuto rilasciati nel tempo, ed il totale complessivo degli ex novo e duplicati, restituendomi una stringa con una dicitura che mi viene visualizzata nella tabella figlio con un div creato in js ma che non è stato creato nel DOM, quindi è dinamico come la tabella, in tutto questo cercavo di creare un paginatore, nel php faccio restituire un massimo di 5 record per pagina, per cui se un dipendente ha un numero di badge inferiori o pari a 5 mi restituisce solo una pagina, viceversa il paginatore calcola il numero di pagine e mi visualizza un numero di pulsanti tanti quanto sono le pagine, compreso di pulsante precedente-successivo-inizio-fine, ora le ho provato tutte dal div posizionato nel DOM sotto la tabella figlio, al tfoot della tabella figlio, ma niente il paginatore non viene visualizzato, all'espansione della tabella figlio i record restituiti sono 5, o meno, quando sono più di 5 visualizza solo i primi 5 ma ovviamente non avendo il paginatore non posso scorrerli, ho anche validato il json resituito dalla query e mi riporta tutto, numero di pagina corrente, totale delle pagine, totale record totale nuovi badge, totale duplicati, totale complessivo e il dettaglio complessivo cn nome cognome del dipendente e data odierna,
insomma mi riporta tutto ma io non riesco a farlo visualizzare sto maledetto paginatore, posto tutti i codici dall'htm al js e al php così da riuscire a farvi un quadro completo , e sperando che qualcuno possa aiutarmi a capire come fare.
Vi ringrazio, buona Domenica.
inizio con il json restituito:
{ "data": [ { "idbadge": 3092, "iddip": 7, "nbadge": "000289", "nfc": "0090000816440", "richiesto": "02/10/2019", "rilascio": "02/10/2019", "causale": "RILASCIO NFC", "rilascioper": "DUPLICATO", "foto": "SI" }, { "idbadge": 7, "iddip": 7, "nbadge": "000289", "nfc": "0000000000000", "richiesto": "02/01/2015", "rilascio": "02/01/2015", "causale": "ASSUNZIONE", "rilascioper": "NUOVO BADGE", "foto": "NO" } ], "pagina": 1, "totalPages": 1, "totalRecords": 2, "total_nuovi_badge": 1, "total_duplicati": 1, "total_badge": 2, "dettaglioBadge": "Al dipendente XXXXXXX XXXXXX, alla data del 21/04/2024, sono stati rilasciati N° 1 Badge Ex Novo - N° 1 Badge Duplicati - per un totale di N° 2 Badge.
Passo PHP
<?php
require_once('connessione.php');
header('Content-Type: application/json');
try {
$iddip = isset($_POST['iddip']) ? $_POST['iddip'] : 0;
$pagina = isset($_POST['pagina']) ? (int)$_POST['pagina'] : 1;
$badgePerPage = isset($_POST['badgePerPage']) ? (int)$_POST['badgePerPage'] : 5;
$offset = ($pagina - 1) * $badgePerPage;
$fetchdata = ['data' => []];
$total_nuovi_badge = 0;
$total_duplicati = 0;
// Query per ottenere nome e cognome del dipendente
$infoQuery = "SELECT cognome, nome FROM dipendente WHERE iddip = :iddip";
$infoStmt = $pdo->prepare($infoQuery);
$infoStmt->bindParam(':iddip', $iddip, PDO::PARAM_INT);
$infoStmt->execute();
$info = $infoStmt->fetch(PDO::FETCH_ASSOC);
// Query per i dettagli dei badge con paginazione
$detailQuery = "SELECT
badge.idbadge,
badge.iddip,
badge.nbadge,
badge.nfc,
DATE_FORMAT(badge.drichiesta,'%d/%m/%Y') AS richiesto,
DATE_FORMAT(badge.drilascio,'%d/%m/%Y') AS rilascio,
badge.causale,
badge.rilascioper,
badge.foto
FROM badge
WHERE badge.iddip = :iddip
ORDER BY badge.drilascio desc
LIMIT :limit OFFSET :offset";
$statement = $pdo->prepare($detailQuery);
$statement->bindParam(':iddip', $iddip, PDO::PARAM_INT);
$statement->bindParam(':limit', $badgePerPage, PDO::PARAM_INT);
$statement->bindParam(':offset', $offset, PDO::PARAM_INT);
$statement->execute();
while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
$fetchdata['data'][] = $row;
}
// Query per il conteggio totale dei badge per la paginazione
$totalQuery = "SELECTCOUNT(*) AS total FROM badge WHERE iddip = :iddip";
$totalStmt = $pdo->prepare($totalQuery);
$totalStmt->bindParam(':iddip', $iddip, PDO::PARAM_INT);
$totalStmt->execute();
$totalResult = $totalStmt->fetch(PDO::FETCH_ASSOC);
$totalRecords = $totalResult['total'];
// Query per il conteggio dei nuovi badge e duplicati
$countQuery = "SELECT
rilascioper, COUNT(*) AS count
FROM badge
WHERE iddip = :iddip
GROUP BY rilascioper";
$countStatement = $pdo->prepare($countQuery);
$countStatement->bindParam(':iddip', $iddip, PDO::PARAM_INT);
$countStatement->execute();
while ($countRow = $countStatement->fetch(PDO::FETCH_ASSOC)) {
if ($countRow['rilascioper'] === 'NUOVO BADGE') {
$total_nuovi_badge = $countRow['count'];
} elseif ($countRow['rilascioper'] === 'DUPLICATO') {
$total_duplicati = $countRow['count'];
}
}
$total_badge = $total_nuovi_badge + $total_duplicati;
$nomeCompleto = "{$info['cognome']} {$info['nome']}";
$dataOdierna = date('d/m/Y');
$dettaglioBadge = "Al dipendente $nomeCompleto, alla data del $dataOdierna, sono stati rilasciati N° $total_nuovi_badge Badge Ex Novo - N° $total_duplicati Badge Duplicati - per un totale di N° $total_badge Badge.";
echojson_encode([
'data' => $fetchdata['data'],
'pagina' => $pagina,
'totalPages' => ceil($totalRecords / $badgePerPage),
'totalRecords' => $totalRecords,
'total_nuovi_badge' => $total_nuovi_badge,
'total_duplicati' => $total_duplicati,
'total_badge' => $total_badge,
'dettaglioBadge' => $dettaglioBadge
], JSON_UNESCAPED_UNICODE);
} catch (PDOException$e) {
error_log("Errore durante l'esecuzione della query: ".$e->getMessage());
echojson_encode(['error' => 'Si è verificato un errore nel server.'], JSON_UNESCAPED_UNICODE);
}
?>
il JS
// Dichiarazione e inizializzazione delle variabili per la paginazione
const recordsPerPage = 5; // Numero di record per pagina
let currentPage = 1; // Pagina corrente iniziale
// Funzione per recuperare i dati della pagina dal server
function fetchPage(page, search = "") {
const params = new URLSearchParams();
params.append("page", page);
params.append("search", search); // Aggiunto per supportare la ricerca
params.append("recordsPerPage", recordsPerPage);
//inizializzazione tabella dipendenti e caricamento dati dinamici in tabella
fetch("../php/dipend.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params,
})
.then((response) => response.json())
.then((data) => {
const tbody = document
.getElementById("tableDipendenti")
.getElementsByTagName("tbody")[0];
tbody.innerHTML = ""; // Pulisci la tbody prima di aggiungere nuove righe
data.data.forEach((row) => {
const tr = document.createElement("tr");
tr.setAttribute('data-id', row.iddip); // Assicurati che ogni riga abbia un data-id
tr.innerHTML = `
<td class="icon-cell"><i class="fa fa-arrow-circle-o-right fa-2x" aria-hidden="true" onclick="toggleBadgeDetails(event, this.parentElement.parentElement.getAttribute('data-id'))"></i></td>
<td class="dip-data-cell">${row.matr}</td>
<td class="dip-data-cell">${row.cognome}</td>
<td class="dip-data-cell">${row.nome}</td>
<td class="dip-data-cell">${row.nascita}</td>
<td class="dip-data-cell">${row.matrcomune}</td>
<td class="dip-data-cell">${row.assunzione}</td>
<td class="dip-data-cell">${row.iniznomin}</td>
<td class="dip-data-cell"><img src="${row.foto}" style="height:50px; width:50px;"></td>
<td class="dip-data-cell">${row.stato}</td>
<td class="hidden-id">${row.totbadge}</td>
`;
tr.addEventListener("click", function () {
const idDipendente = row.iddip;
// Mostra l'ID del dipendente in un alert
alert("ID del dipendente cliccato: " + idDipendente);
});
tbody.appendChild(tr);
});
updatePagination(data.totalPages, currentPage);
})
.catch((error) => {
console.error("Errore di rete:", error);
});
}
// Seleziona tutte le righe della tabella padre
const rows = document.querySelectorAll("#parentTable tbody tr");
// Funzione per aggiornare il paginatore
function updatePagination(totalPages, currentPage) {
const container = document.getElementById("pagination");
container.innerHTML = ""; // Pulisci la paginazione esistente
// Pulsante "Inizio"
const startButton = createPageButton("Inizio", 1);
startButton.disabled = currentPage === 1; // Disabilita se sei alla prima pagina
container.appendChild(startButton);
// Pulsante "Precedente"
const prevButton = createPageButton("Precedente", currentPage - 1);
prevButton.disabled = currentPage === 1; // Disabilita se sei alla prima pagina
container.appendChild(prevButton);
// Pulsanti numerici
for (
let i = Math.max(1, currentPage - 2);
i <= Math.min(totalPages, currentPage + 2);
i++
) {
const numButton = createPageButton(i, i);
numButton.disabled = i === currentPage; // Disabilita il pulsante della pagina corrente
container.appendChild(numButton);
}
// Pulsante "Successivo"
const nextButton = createPageButton("Successivo", currentPage + 1);
nextButton.disabled = currentPage === totalPages; // Disabilita se sei all'ultima pagina
container.appendChild(nextButton);
// Pulsante "Fine"
const endButton = createPageButton("Fine", totalPages);
endButton.disabled = currentPage === totalPages; // Disabilita se sei all'ultima pagina
container.appendChild(endButton);
}
// Funzione per creare un pulsante di pagina
function createPageButton(text, page) {
const button = document.createElement("button");
button.textContent = text;
button.addEventListener("click", () => {
fetchPage(page);
currentPage = page; // Aggiorna la pagina corrente
});
return button;
}
// Chiamata iniziale per recuperare la prima pagina dei dati
fetchPage(currentPage);
// Gestore dell'input di ricerca
document.getElementById("searchInput").addEventListener("input", function () {
const searchValue = this.value;
fetchPage(1, searchValue); // Chiama fetchPage con il valore di ricerca
currentPage = 1; // Reset della pagina corrente a 1 dopo una ricerca
// Gestore del click del pulsante di ricerca
document
.getElementById("resetButton")
.addEventListener("click", function () {
const searchValue = document.getElementById("searchInput").value;
fetchPage(1, searchValue); // Chiama fetchPage con il valore di ricerca
currentPage = 1; // Reset della pagina corrente a 1 dopo una ricerca
document.getElementById("searchInput").value = ""; // Pulisce il campo di input della ricerca
});
//---------------------------------------------------------------------------------------------------------------------------------
// si inizializza il collapse per la tabella dei badge
// Funzione per espandere/collassare i dettagli del badge
function toggleBadgeDetails(event, idDipendente) {
event.stopPropagation(); // Previene la propagazione dell'evento
const icon = event.target; // 'icon' definita correttamente qui come l'elemento su cui si è cliccato.
const tr = icon.closest('tr');
const dipId = tr.getAttribute('data-id');
const isExpanded = icon.classList.contains("fa-arrow-circle-o-down"); // Controlla se l'icona indica che i dettagli sono attualmente espansi.
icon.classList.toggle("fa-arrow-circle-o-right"); // Alterna tra indicare un dettaglio non espanso
icon.classList.toggle("fa-arrow-circle-o-down"); // e un dettaglio espanso.
const detailsRowId = "details-row-" + dipId;
let detailsRow = document.getElementById(detailsRowId);
if (!detailsRow) {
detailsRow = document.createElement("tr");
detailsRow.id = detailsRowId;
detailsRow.innerHTML = `<td colspan="11"><div id='details-content-${dipId}' class='details-content'>Caricamento...</div></td>`;
tr.parentNode.insertBefore(detailsRow, tr.nextSibling);
fetchBadgeDetails(dipId, detailsRowId);
} else {
const detailsContent = document.getElementById(`details-content-${dipId}`);
detailsContent.parentNode.parentNode.style.display = isExpanded ? "none" : "table-row";
}
}
function fetchBadgeDetails(idDipendente, detailsRowId) {
fetch("../php/countbdgpag.php", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `iddip=${idDipendente}`,
})
.then((response) => response.json())
.then((data) => {
const detailsContent = document.getElementById(
`details-content-${idDipendente}`
);
let badgesHTML = `<table class="badge-details">
<thead>
<tr>
<th class="hidden-id">ID BADGE</th>
<th class="hidden-id">ID DIPENDENTE</th>
<th>BADGE N°</th>
<th>NFC</th>
<th>RICHIESTO IL</th>
<th>RILASCIATO IL</th>
<th>CAUSALE</th>
<th>RILASCIO COME</th>
<th>FOTO</th>
</tr>
</thead>
<tbody>`;
data.data.forEach((badge) => {
badgesHTML += `<tr onclick="alert('ID Badge cliccato: ${badge.idbadge}')">
<td class="hidden-id">${badge.idbadge}</td>
<td class="hidden-id">${badge.iddip}</td>
<td>${badge.nbadge}</td>
<td>${badge.nfc}</td>
<td>${badge.richiesto}</td>
<td>${badge.rilascio}</td>
<td>${badge.causale}</td>
<td>${badge.rilascioper}</td>
<td>${badge.foto}</td>
</tr>`;
});
badgesHTML += `</tbody></table>`;
badgesHTML += `<div>${data.dettaglioBadge}</div>`; // Aggiungi il dettaglio dei conteggi dei badge
detailsContent.innerHTML = badgesHTML; // Inserisce i dettagli dei badge nel contenitore appropriato
})
.catch((error) => {
console.error(
"Errore durante il caricamento dei dettagli dei badge:",
error
);
detailsContent.innerHTML = "Errore nel caricamento dei dati.";
});
}
// PAGINATORE BADGE
function updateBadgePagination(totalPages, currentPage, idDipendente) {
const pagination = document.getElementById('badgePagination');
pagination.innerHTML = ""; // Pulizia della paginazione
console.log(`Creating pagination for ${totalPages} pages, current page: ${currentPage}`);
// Pulsante per andare alla prima pagina
const firstPageBtn = document.createElement('button');
firstPageBtn.textContent = "Inizio";
firstPageBtn.onclick = () => fetchBadgeDetails(idDipendente, 1);
firstPageBtn.disabled = currentPage === 1;
pagination.appendChild(firstPageBtn);
// Pulsante per andare alla pagina precedente
const prevPageBtn = document.createElement('button');
prevPageBtn.textContent = "Precedente";
prevPageBtn.onclick = () => fetchBadgeDetails(idDipendente, currentPage - 1);
prevPageBtn.disabled = currentPage === 1;
pagination.appendChild(prevPageBtn);
// Pulsanti per le pagine numerate
for (let i = 1; i <= totalPages; i++) {
let pageBtn = document.createElement('button');
pageBtn.textContent = i;
pageBtn.onclick = () => fetchBadgeDetails(idDipendente, i);
pageBtn.disabled = i === currentPage;
pagination.appendChild(pageBtn);
}
console.log(`Creating pagination for ${totalPages} pages, current page: ${currentPage}`);
// Pulsante per andare alla pagina successiva
const nextPageBtn = document.createElement('button');
nextPageBtn.textContent = "Successivo";
nextPageBtn.onclick = () => fetchBadgeDetails(idDipendente, currentPage + 1);
nextPageBtn.disabled = currentPage === totalPages;
pagination.appendChild(nextPageBtn);
// Pulsante per andare all'ultima pagina
const lastPageBtn = document.createElement('button');
lastPageBtn.textContent = "Fine";
lastPageBtn.onclick = () => fetchBadgeDetails(idDipendente, totalPages);
lastPageBtn.disabled = currentPage === totalPages;
pagination.appendChild(lastPageBtn);
}
ed infine HTML
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dashboard Dipendenti</title>
<link rel="icon" href="../img/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="../css/stile.css">
</head>
<body>
<h1>Elenco Dipendenti</h1>
<!-- Contenitore principale per la ricerca, tabella e paginazione -->
<div id="mainContainer">
<div id="mainTableContainer">
<div id="dipendentiContainer">
<div id="search-box">
<input type="text" id="searchInput" placeholder="Cerca dipendente...">
<button id="resetButton" class="hide">×</button> <!-- Pulsante per cancellare la ricerca -->
</div> <!-- Div per la casella di ricerca -->
<table id="tableDipendenti" class="display" style="width:100%">
<thead>
<tr class="header-row">
<th class="first-table"></th>
<th class="first-table">MATRICOLA:</th>
<th class="first-table">COGNOME:</th>
<th class="first-table">NOME:</th>
<th class="first-table">DATA DI NASCITA:</th>
<th class="first-table">CODICE SISPI:</th>
<th class="first-table">DATA DI ASSUNZIONE:</th>
<th class="first-table">INTESTAZIONE BADGE:</th>
<th class="first-table">FOTO:</th>
<th class="first-table">STATO:</th>
<th class="hidden-id">TOTALE BADGE:</th>
</tr>
</thead>
<tbody>
<!-- Dati tabella -->
</tbody>
</table>
<div id="pagination" class="pagination"></div>
</div>
<div id="badgeTableContainer" style="display: none;">
<table id="badgeTable">
<thead>
<!-- Intestazioni tabella badge -->
</thead>
<tbody>
<!-- Dati tabella badge -->
</tbody>
<tfoot>
<tr>
<td colspan="9">
<div id="badgePagination" class="pagination">
<!-- Qui verranno aggiunti i bottoni di paginazione via JavaScript -->
</div>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<scriptsrc="../js/popolatab.js"></script>
</body>
</html>
e se posso allego l'immagine di come dovrebbe essere la tabella