.setTitle('Visor de Hojas de Google Sheet');
}
en el HTML
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Visor de Hojas de Google Sheet con DataTables</title>
<!-- jQuery -->
<!-- DataTables CSS and JS -->
<!-- Include a recent jQuery version again for good measure, sometimes needed -->
<style>
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
.container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 25px; }
h1, h2 { color: #333; }
label { display: block; margin-bottom: 8px; font-weight: bold; }
select { padding: 10px; font-size: 1em; width: 100%; max-width: 400px; margin-bottom: 20px; border: 1px solid #ccc; border-radius: 4px; }
#status, #dataStatus { color: #555; font-style: italic; margin-top: 10px; padding: 8px; border-radius: 4px; }
#status.success, #dataStatus.success { background-color: #e6ffed; border-left: 3px solid #4caf50; }
#status.error, #dataStatus.error { background-color: #ffebee; border-left: 3px solid #f44336; }
#status.loading, #dataStatus.loading { background-color: #e3f2fd; border-left: 3px solid #2196f3; }
#sheetDataTable { width: 100% !important; }
/* DataTables custom styling for better appearance */
.dataTables_wrapper .dataTables_paginate .paginate_button { padding: 0.3em 0.8em; }
.dataTables_wrapper .dataTables_filter input { margin-left: 0.5em; padding: 6px; border: 1px solid #ccc; border-radius: 4px; }
.dataTables_wrapper .dataTables_length select { padding: 6px; border: 1px solid #ccc; border-radius: 4px; width: auto; }
</style>
</head>
<body>
<div class="container">
<h1>Selecciona una Hoja del Archivo</h1>
<label for="sheetSelector">Hojas Disponibles:</label>
<select id="sheetSelector" disabled>
<option value="">Cargando hojas...</option>
</select>
<p id="status">Inicializando...</p>
</div>
<div class="container">
<h2>Datos de la Hoja Seleccionada:</h2>
<div id="dataTableContainer"></div>
<p id="dataStatus">Selecciona una hoja del desplegable de arriba para ver sus datos.</p>
</div>
<script>
let dataTableInstance = null; // Variable to hold the DataTables instance
// Function to update status messages
function updateStatus(elementId, message, type = 'info') {
const el = document.getElementById(elementId);
if (el) {
el.textContent = message;
el.className = type; // Add class for styling (success, error, loading)
}
console.log(`Status [${elementId} - ${type}]: ${message}`); // Log status to console
}
// Function to load sheet names from Google Sheet
function loadSheetNames() {
updateStatus('status', 'Solicitando nombres de hojas...', 'loading');
google.script.run
.withSuccessHandler(populateDropdown)
.withFailureHandler(function(error) {
console.error('Error al cargar nombres de hojas:', error);
updateStatus('status', 'Error al cargar hojas: ' + error.message, 'error');
})
.getSheetNames();
}
function populateDropdown(sheetNames) {
console.log("populateDropdown: Recibidos nombres de hojas:", sheetNames);
const selectElement = document.getElementById('sheetSelector');
selectElement.innerHTML = ''; // Clear existing options
if (sheetNames && sheetNames.length > 0) {
const defaultOption = document.createElement('option');
defaultOption.value = "";
defaultOption.textContent = "--- Selecciona una hoja ---";
selectElement.appendChild(defaultOption);
sheetNames.forEach(function(name) {
const option = document.createElement('option');
option.value = name; // Use the sheet name as the value
option.textContent = name;
selectElement.appendChild(option);
});
updateStatus('status', 'Hojas cargadas correctamente. Selecciona una.', 'success');
selectElement.disabled = false;
// Load the first sheet automatically if there are sheets
// COMENTAR ESTO TEMPORALMENTE:
// if (sheetNames.length > 0) {
// fetchSheetData(sheetNames[0]);
// }
} else {
const option = document.createElement('option');
option.value = "";
option.textContent = "No se encontraron hojas.";
selectElement.appendChild(option);
selectElement.disabled = true;
updateStatus('status', 'No se pudo cargar la lista de hojas.', 'error');
}
}
// Function to handle failure in loading sheet names (more robust error handling)
function onSheetNamesFailure(error) {
console.error('Error al cargar nombres de hojas:', error);
const selectElement = document.getElementById('sheetSelector');
selectElement.innerHTML = '<option value="">Error al cargar hojas</option>';
selectElement.disabled = true;
updateStatus('status', 'Error crítico al cargar nombres de hojas: ' + error.message, 'error');
}
// Function to fetch data for a selected sheet
function fetchSheetData(sheetName) {
updateStatus('dataStatus', `Cargando datos de "${sheetName}"...`, 'loading');
// Add this console.log to see the value being passed
console.log(`fetchSheetData: Llamando a getSheetData con sheetName: "${sheetName}"`);
google.script.run
.withSuccessHandler(function(response) {
console.log("Respuesta recibida:", response); // Add this log to see the response
if (response && response.success) {
if (response.data.length === 0) {
updateStatus('dataStatus', `La hoja "${sheetName}" está vacía.`, 'info');
clearDataTable();
} else {
initializeDataTable(response.headers, response.data, sheetName);
}
} else {
updateStatus('dataStatus', 'Error: ' + (response ? response.message : 'Respuesta no válida'), 'error');
clearDataTable();
}
})
.withFailureHandler(function(error) {
console.error('Error al cargar datos:', error);
updateStatus('dataStatus', 'Error al cargar datos: ' + error.message, 'error');
clearDataTable();
})
.getSheetData(sheetName);
}
// Function to clear and destroy the existing DataTables instance
function clearDataTable() {
if (dataTableInstance) {
try {
dataTableInstance.destroy();
} catch(e) {
console.log("Error al destruir DataTable:", e);
}
dataTableInstance = null;
}
$('#dataTableContainer').empty(); // Clear the container div
}
// Function to initialize DataTables
function initializeDataTable(headers, tableData, sheetName) {
console.log("Headers:", headers);
console.log("Datos:", tableData);
clearDataTable(); // Clear any existing table
// Ensure headers are valid
if (!headers || headers.length === 0) {
updateStatus('dataStatus', "No se pudieron determinar encabezados.", 'error');
return;
}
// Create the table element
$('#dataTableContainer').html('<table id="sheetDataTable" class="display compact hover stripe" style="width:100%;"></table>');
try {
dataTableInstance = $('#sheetDataTable').DataTable({
data: tableData,
columns: headers.map((h, i) => ({
title: String(h !== null && h !== undefined ? h : "Columna " + (i + 1)), // Handle null/undefined headers
defaultContent: "" // Ensure empty cells display as empty
})),
responsive: true,
pageLength: 10,
lengthMenu: [ [10, 25, 50, 100, -1], [10, 25, 50, 100, "Todos"] ],
language: {
// Your Spanish language configuration for DataTables
"decimal": "",
"emptyTable": "No hay datos disponibles en la tabla",
"info": "Mostrando _START_ a _END_ de _TOTAL_ entradas",
"infoEmpty": "Mostrando 0 a 0 de 0 entradas",
"infoFiltered": "(filtrado de _MAX_ entradas totales)",
"infoPostFix": "",
"thousands": ",",
"lengthMenu": "Mostrar _MENU_ entradas",
"loadingRecords": "Cargando...",
"processing": "Procesando...",
"search": "Buscar:",
"zeroRecords": "No se encontraron registros coincidentes",
"paginate": {
"first": "Primero",
"last": "Último",
"next": "Siguiente",
"previous": "Anterior"
},
"aria": {
"sortAscending": ": activar para ordenar la columna ascendentemente",
"sortDescending": ": activar para ordenar la columna descendentemente"
}
}
});
updateStatus('dataStatus', `Mostrando ${tableData.length} filas de "${sheetName}"`, 'success');
} catch (e) {
console.error('Error al inicializar DataTable:', e);
updateStatus('dataStatus', 'Error al inicializar DataTable: ' + e.message, 'error');
}
}
// Event listener for dropdown change
document.getElementById('sheetSelector').addEventListener('change', function() {
const sheetName = this.value;
console.log("Hoja seleccionada:", sheetName); // Verify the selected sheet name
if (sheetName) {
fetchSheetData(sheetName);
} else {
clearDataTable();
updateStatus('dataStatus', 'Seleccione una hoja para ver los datos.', 'info');
}
});
// Load sheet names when the page loads
window.addEventListener('load', function() {
loadSheetNames();
});
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<title>Visor de Hojas de Google Sheet con DataTables</title>
<!-- jQuery -->
<!-- DataTables CSS and JS -->
<!-- Include a recent jQuery version again for good measure, sometimes needed -->
<style>
body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f4; color: #333; }
.container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); margin-bottom: 25px; }
h1, h2 { color: #333; }
label { display: block; margin-bottom: 8px; font-weight: bold; }
select { padding: 10px; font-size: 1em; width: 100%; max-width: 400px; margin-bottom: 20px; border: 1px solid #ccc; border-radius: 4px; }
#status, #dataStatus { color: #555; font-style: italic; margin-top: 10px; padding: 8px; border-radius: 4px; }
#status.success, #dataStatus.success { background-color: #e6ffed; border-left: 3px solid #4caf50; }
#status.error, #dataStatus.error { background-color: #ffebee; border-left: 3px solid #f44336; }
#status.loading, #dataStatus.loading { background-color: #e3f2fd; border-left: 3px solid #2196f3; }
#sheetDataTable { width: 100% !important; }
/* DataTables custom styling for better appearance */
.dataTables_wrapper .dataTables_paginate .paginate_button { padding: 0.3em 0.8em; }
.dataTables_wrapper .dataTables_filter input { margin-left: 0.5em; padding: 6px; border: 1px solid #ccc; border-radius: 4px; }
.dataTables_wrapper .dataTables_length select { padding: 6px; border: 1px solid #ccc; border-radius: 4px; width: auto; }
</style>
</head>
<body>
<div class="container">
<h1>Selecciona una Hoja del Archivo</h1>
<label for="sheetSelector">Hojas Disponibles:</label>
<select id="sheetSelector" disabled>
<option value="">Cargando hojas...</option>
</select>
<p id="status">Inicializando...</p>
</div>
<div class="container">
<h2>Datos de la Hoja Seleccionada:</h2>
<div id="dataTableContainer"></div>
<p id="dataStatus">Selecciona una hoja del desplegable de arriba para ver sus datos.</p>
</div>
<script>
let dataTableInstance = null; // Variable to hold the DataTables instance
// Function to update status messages
function updateStatus(elementId, message, type = 'info') {
const el = document.getElementById(elementId);
if (el) {
el.textContent = message;
el.className = type; // Add class for styling (success, error, loading)
}
console.log(`Status [${elementId} - ${type}]: ${message}`); // Log status to console
}
// Function to load sheet names from Google Sheet
function loadSheetNames() {
updateStatus('status', 'Solicitando nombres de hojas...', 'loading');
google.script.run
.withSuccessHandler(populateDropdown)
.withFailureHandler(function(error) {
console.error('Error al cargar nombres de hojas:', error);
updateStatus('status', 'Error al cargar hojas: ' + error.message, 'error');
})
.getSheetNames();
}
function populateDropdown(sheetNames) {
console.log("populateDropdown: Recibidos nombres de hojas:", sheetNames);
const selectElement = document.getElementById('sheetSelector');
selectElement.innerHTML = ''; // Clear existing options
if (sheetNames && sheetNames.length > 0) {
const defaultOption = document.createElement('option');
defaultOption.value = "";
defaultOption.textContent = "--- Selecciona una hoja ---";
selectElement.appendChild(defaultOption);
sheetNames.forEach(function(name) {
const option = document.createElement('option');
option.value = name; // Use the sheet name as the value
option.textContent = name;
selectElement.appendChild(option);
});
updateStatus('status', 'Hojas cargadas correctamente. Selecciona una.', 'success');
selectElement.disabled = false;
// Load the first sheet automatically if there are sheets
// COMENTAR ESTO TEMPORALMENTE:
// if (sheetNames.length > 0) {
// fetchSheetData(sheetNames[0]);
// }
} else {
const option = document.createElement('option');
option.value = "";
option.textContent = "No se encontraron hojas.";
selectElement.appendChild(option);
selectElement.disabled = true;
updateStatus('status', 'No se pudo cargar la lista de hojas.', 'error');
}
}
// Function to handle failure in loading sheet names (more robust error handling)
function onSheetNamesFailure(error) {
console.error('Error al cargar nombres de hojas:', error);
const selectElement = document.getElementById('sheetSelector');
selectElement.innerHTML = '<option value="">Error al cargar hojas</option>';
selectElement.disabled = true;
updateStatus('status', 'Error crítico al cargar nombres de hojas: ' + error.message, 'error');
}
// Function to fetch data for a selected sheet
function fetchSheetData(sheetName) {
updateStatus('dataStatus', `Cargando datos de "${sheetName}"...`, 'loading');
// Add this console.log to see the value being passed
console.log(`fetchSheetData: Llamando a getSheetData con sheetName: "${sheetName}"`);
google.script.run
.withSuccessHandler(function(response) {
console.log("Respuesta recibida:", response); // Add this log to see the response
if (response && response.success) {
if (response.data.length === 0) {
updateStatus('dataStatus', `La hoja "${sheetName}" está vacía.`, 'info');
clearDataTable();
} else {
initializeDataTable(response.headers, response.data, sheetName);
}
} else {
updateStatus('dataStatus', 'Error: ' + (response ? response.message : 'Respuesta no válida'), 'error');
clearDataTable();
}
})
.withFailureHandler(function(error) {
console.error('Error al cargar datos:', error);
updateStatus('dataStatus', 'Error al cargar datos: ' + error.message, 'error');
clearDataTable();
})
.getSheetData(sheetName);
}
// Function to clear and destroy the existing DataTables instance
function clearDataTable() {
if (dataTableInstance) {
try {
dataTableInstance.destroy();
} catch(e) {
console.log("Error al destruir DataTable:", e);
}
dataTableInstance = null;
}
$('#dataTableContainer').empty(); // Clear the container div
}
// Function to initialize DataTables
function initializeDataTable(headers, tableData, sheetName) {
console.log("Headers:", headers);
console.log("Datos:", tableData);
clearDataTable(); // Clear any existing table
// Ensure headers are valid
if (!headers || headers.length === 0) {
updateStatus('dataStatus', "No se pudieron determinar encabezados.", 'error');
return;
}
// Create the table element
$('#dataTableContainer').html('<table id="sheetDataTable" class="display compact hover stripe" style="width:100%;"></table>');
try {
dataTableInstance = $('#sheetDataTable').DataTable({
data: tableData,
columns: headers.map((h, i) => ({
title: String(h !== null && h !== undefined ? h : "Columna " + (i + 1)), // Handle null/undefined headers
defaultContent: "" // Ensure empty cells display as empty
})),
responsive: true,
pageLength: 10,
lengthMenu: [ [10, 25, 50, 100, -1], [10, 25, 50, 100, "Todos"] ],
language: {
// Your Spanish language configuration for DataTables
"decimal": "",
"emptyTable": "No hay datos disponibles en la tabla",
"info": "Mostrando _START_ a _END_ de _TOTAL_ entradas",
"infoEmpty": "Mostrando 0 a 0 de 0 entradas",
"infoFiltered": "(filtrado de _MAX_ entradas totales)",
"infoPostFix": "",
"thousands": ",",
"lengthMenu": "Mostrar _MENU_ entradas",
"loadingRecords": "Cargando...",
"processing": "Procesando...",
"search": "Buscar:",
"zeroRecords": "No se encontraron registros coincidentes",
"paginate": {
"first": "Primero",
"last": "Último",
"next": "Siguiente",
"previous": "Anterior"
},
"aria": {
"sortAscending": ": activar para ordenar la columna ascendentemente",
"sortDescending": ": activar para ordenar la columna descendentemente"
}
}
});
updateStatus('dataStatus', `Mostrando ${tableData.length} filas de "${sheetName}"`, 'success');
} catch (e) {
console.error('Error al inicializar DataTable:', e);
updateStatus('dataStatus', 'Error al inicializar DataTable: ' + e.message, 'error');
}
}
// Event listener for dropdown change
document.getElementById('sheetSelector').addEventListener('change', function() {
const sheetName = this.value;
console.log("Hoja seleccionada:", sheetName); // Verify the selected sheet name
if (sheetName) {
fetchSheetData(sheetName);
} else {
clearDataTable();
updateStatus('dataStatus', 'Seleccione una hoja para ver los datos.', 'info');
}
});
// Load sheet names when the page loads
window.addEventListener('load', function() {
loadSheetNames();
});
</script>
</body>
</html>