Guys, how are you? Here's a nice tip to keep your Google Sheet tables tidy without annoying blank rows. To do this, you need to open the Apps Script tools in Google Sheets and activate the Google Sheets API service in the editor.
In the function area, you place this script (please test it thoroughly with prototypes to see if it has any errors). I haven't tested it on a large scale yet, but I'm seeing good results.
how does it work?
Scan all rows in column A.
Detect which ones are empty.
If there’s more than one empty row, delete all except the last.
Perform deletions from bottom to top to avoid index shifting issues.
This script checks column A of the active sheet and finds all empty rows.
If more than one empty row exists, it deletes all but the last one to keep the sheet tidy without removing the blank row that AppSheet sometimes expects for new entries.
It executes the deletions in a batch, starting from the bottom, using the Google Sheets API to avoid index mismatches during row removal.
The only condition will be that you place the ID (required) in column A. Why? Because the script doesn't go through the entire table, but only column A. This is because it's faster, and we know that the ID field is the only one that is always required in our tables.
function eliminarFilasVaciasDeUnaVez() {
var hoja = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var spreadsheetId = SpreadsheetApp.getActiveSpreadsheet().getId();
var sheetId = hoja.getSheetId();
// Obtener todos los valores de la columna A hasta la última fila con contenido
// o hasta el máximo de filas si la columna A está vacía pero otras tienen datos.
// Para ser más exhaustivos, podríamos usar hoja.getMaxRows() si la columna A
// puede estar vacía incluso si hay datos en otras columnas más allá de A.
var maxFilas = hoja.getMaxRows();
if (maxFilas === 0) {
Logger.log("La hoja no tiene filas.");
return;
}
var rango = hoja.getRange("A1:A" + maxFilas);
var valores = rango.getValues();
var indicesFilasVacias = []; // Almacenará los índices 0-based de las filas vacías
// Recorrer las filas para encontrar todas las que están vacías en la columna A
for (var i = 0; i < valores.length; i++) {
if (valores[i][0] === "" || valores[i][0] == null) { // Considerar "" y null como vacío
indicesFilasVacias.push(i); // i es el índice 0-based de la fila
}
}
if (indicesFilasVacias.length <= 1) {
Logger.log("No hay suficientes filas vacías para eliminar (se encontró " + indicesFilasVacias.length + ", se necesita más de una).");
return;
}
// Queremos conservar la última fila vacía encontrada (la que tiene el índice más alto).
// Por lo tanto, eliminaremos todas las filas vacías excepto la última en la lista 'indicesFilasVacias'.
// 'slice' crea una nueva lista con los elementos a borrar.
// El último elemento de 'indicesFilasVacias' es el que se conservará.
var indicesParaBorrar = indicesFilasVacias.slice(0, indicesFilasVacias.length - 1);
if (indicesParaBorrar.length === 0) {
Logger.log("Después de la lógica de 'conservar una', no quedan filas para borrar.");
return;
}
// Crear las solicitudes de eliminación para la API
var requests = indicesParaBorrar.map(function(rowIndex) {
// rowIndex es 0-based y se refiere a la fila real en la hoja.
return {
"deleteDimension": {
"range": {
"sheetId": sheetId,
"dimension": "ROWS",
"startIndex": rowIndex, // 0-indexed, inclusivo
"endIndex": rowIndex + 1 // 0-indexed, exclusivo
}
}
};
});
// ¡Importante! Para evitar problemas con el cambio de índices durante la eliminación,
// las solicitudes de eliminación deben procesarse de abajo hacia arriba (índices más altos primero).
// Por eso, ordenamos las 'requests' en orden descendente según 'startIndex'.
requests.sort(function(a, b) {
return b.deleteDimension.range.startIndex - a.deleteDimension.range.startIndex;
});
// Ejecutar la operación por lotes
try {
Sheets.Spreadsheets.batchUpdate({ "requests": requests }, spreadsheetId);
Logger.log(indicesParaBorrar.length + " filas vacías eliminadas de una vez.");
} catch (e) {
Logger.log("Error al eliminar filas: " + e.toString());
SpreadsheetApp.getUi().alert("Error al eliminar filas: " + e.toString());
}
}
Process
The idea is that it deletes the blank rows (in batch) and not one by one, leaving a single blank row at the end (since if you use Google Sheets tables, they must have at least one blank row).
While the script is to monitor changes when you add a row to the appsheet, it also works outside of the appsheet since it belongs to the Google Sheet.
Well, I hope you can test it with sheets that don't compromise your data, and then let me know how it goes.
Hi @Gustavo_Eduardo
Thank you for your tip.
To use this code, do I only need to add Service "Goodle Sheets API"? This makes the code work well.
BTW ChatGPT also suggests another one that "Since advanced services actually use Google Cloud Platform's APIs, they also need to be enabled in the GCP Console".
Happy to hear your thoughts.
Hey friend! How are you? I hope you're doing well! For now, I'm just running it with the Google Sheet API service, but I don't think enabling another service will interrupt its functionality. Give it a try and let me know. In the meantime, I'll explain the step-by-step process.
In the sheet where you want to add the script, go to the Apps Script console. Inside, paste the code and save the project with a name, for example, "delete_blank_rows." Then, enable at least the Google Sheet API service. After that, add a trigger (I use "on change" and weekly notifications). Grant the necessary permissions, and once everything is enabled, test it out. You can add 10 rows to the sheet, and you'll see how 9 are deleted, leaving only one blank.
I think that should work!
Hi.
Although I have not used the "Google Sheets API", I managed to create the Apps Script.
I made a stand alone Apps Script Project based your code and a bot-Call a script at AppSheet. It works well
Thank you.
Great. I built that logic to work outside of AppSheet, but if it's working well for you, I think it's a good alternative!