google-sheetsgoogle-apps-scripterror-handling

Google Sheet Script - Removing a gap of blank cells within a range to keep a list compact and tidy?


I need help with a google app script. I want to update the script below. I need to remove the current logic of the script that shifts rows up when there are gaps of blank cells within the range B28:X500, when a row is cleared.

The issue with it is: The script want to shift ALL the rows with blank cells within the range B28:X500 (even the ones from the bottom of the sheet witch I don't care about) + I got running time troubleshooting and basically this isnt what I want.

What I want is : After the script has been clearing a row based on conditions On "Task Masterlist" sheet, it shifts up the range of cell below the row that has been cleared (From colum B:X. This fonction would be based on column E to shift the cells up when the range is cleared within that range of the sheet B28:X500.

The goal is to remove any gaps and keep the list compact and tidy...

I'll share a picture to illustrate better what I want:

You see this is a task list, in the column E are the tasks...when this script is running it will create blank cells to appear in the sheet as the completed tasks are archived on anothe sheet. I want the script to remain almost the same as it is but to close the gaps that are apearing within the list but only for the cells from the column B to X. The types of gaps you see between the tasks in the picture, this is what I want to get rid of.

As a consequence, it would move the remaining task up (witch are in colum E) and keep the task list compact and tidy. Ideally, I would like the script to only search for the gaps between the tasks instead of looking at all the sheet, for quicker action..if it could look for text in column E as a rule to move the range of cells up for exemple. Also, please remember I don't want to shift up the complete row, just the range of cell between B28:X500 if a series of blank cells is found within the column E to avoid gaps in the following rows. How do I write this?

Here's the script I am currently working on:

* @OnlyCurrentDoc
 */
function archiveTasks() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var taskSheet = ss.getSheetByName("Task Masterlist");
  var archiveSheet = ss.getSheetByName("Archive");
  
  // Define the range to check
  var range = taskSheet.getRange("B28:X500");
  var values = range.getValues();
  
  // Loop through the rows in reverse order
  for (var i = values.length - 1; i >= 0; i--) {
    if (values[i][0] === true) { // Check if the first column (B) is "True"
      // Get the row to move
      var row = values[i];
      
      // Find the first empty row in the Archive sheet starting from row 18
      var emptyRow = findFirstEmptyRow(archiveSheet, 18);
      
      // Move the row to the Archive sheet
      archiveSheet.getRange("B" + emptyRow + ":X" + emptyRow).setValues([row]);
      
      // Add the current date and time to column Y in the Archive sheet
      var timeZone = "America/Toronto"; // Set your time zone
      var date = new Date();
      var formattedDate = Utilities.formatDate(date, timeZone, "yyyy-MM-dd HH:mm:ss");
      archiveSheet.getRange("Y" + emptyRow).setValue(formattedDate);
      
      // Clear the specific range in the Task Masterlist sheet but retain formulas
      var formulas = taskSheet.getRange(28 + i, 2, 1, 23).getFormulas()[0];
      taskSheet.getRange(28 + i, 2, 1, 23).clearContent();
      taskSheet.getRange(28 + i, 2, 1, 23).setFormulas([formulas]);
      
      // Move the rows below up to remove gaps
      shiftRowsUp(taskSheet, 28 + i, 500);
    }
  }
  
  // Sort the remaining tasks by the due date (column F)
  taskSheet.getRange("B28:X500").sort({column: 6, ascending: true});
  
  // Ensure the sheet always has 500 rows with the same format and formulas
  maintainRowCount(taskSheet, 500);
}

function findFirstEmptyRow(sheet, startRow) {
  var data = sheet.getRange("B" + startRow + ":B").getValues();
  for (var i = 0; i < data.length; i++) {
    if (!data[i][0]) {
      return startRow + i;
    }
  }
  return startRow + data.length;
}

function shiftRowsUp(sheet, startRow, endRow) {
  for (var i = startRow; i < endRow; i++) {
    var currentRange = sheet.getRange(i, 2, 1, 23);
    var nextRange = sheet.getRange(i + 1, 2, 1, 23);
    var nextValues = nextRange.getValues();
    var nextFormulas = nextRange.getFormulas();
    
    currentRange.setValues(nextValues);
    currentRange.setFormulas(nextFormulas);
  }
  
  // Clear the last row in the range
  sheet.getRange(endRow, 2, 1, 23).clearContent();
}

function maintainRowCount(sheet, targetRowCount) {
  var lastRow = sheet.getLastRow();
  var numRowsToAdd = targetRowCount - lastRow;
  if (numRowsToAdd > 0) {
    var sourceRange = sheet.getRange(400, 2, 1, 23); // Copying from row 400
    for (var j = 0; j < numRowsToAdd; j++) {
      var targetRange = sheet.getRange(lastRow + 1 + j, 2, 1, 23);
      sourceRange.copyTo(targetRange);
    }
  }
}
 

I tryied to write this script in various ways but havent found a correct formulation for what I am trying to achieve.


Solution

  • This was important to me that the gaps were to be removed automatically while the script would run. I explain myself, the script itself would create these gaps while the completed tasks would be move to the archive Sheet so I wanted a function "that would repair" the gaps that were created in this process and I wanted this to run by itself.

    So here's how I've fixed this for my script... This string of code was added to the script and what this does is:

    After the completed tasks are moved to Archive sheet,it sorts the remaining tasks in the range B28:X500 by the due date (in column F) in ascending order. This helps automaticaly to remove any gaps by shifting up the coresponding range and keep the task list compact and tidy.

    Here's the code:

    // Sort the remaining tasks by the due date (column F)
    taskSheet.getRange("B28:X500").sort({column: 6, ascending: true});
    

    I've used the date column (F) instead of the tasks column (E) because it was simpler. This works perfectly for me!

    Hope this is helpfull!