How to freeze a range of cells when a checkbox is

2020-04-02 07:18发布

问题:

Screenshot for the sheet:

I just need someone to help me write simple code to freeze a range of cells when a certain checkbox is clicked.

I would like it so that when I click on the 'Complete' checkbox, all of the ones above it cannot be edited or changed anymore. Vise Versa when the 'Complete' checkbox is unchecked the ones above are editable. That simple.

The purpose of the sheet is to take attendance for a class. When I am done taking the attendance I don't want to be able to change it anymore (or risk clicking on the wrong checkbox). That's why the complete button is there.

Can anyone write the code for me, please?

(Freeze or seal or protect)

This code is not working (I am a beginner so sorry)

function onEdit() {
  var sheet = SpreadsheetApp.getActive();;
  var completedRow = sheet.getDataRange();  
  
  for (i = 2; i < 18; i++){
    var isComplete = source.getRange(countRow, i).getValue();
    
    if (isComplete === true){
      source.getRange(2, i, countRow-1).protect();
    }
  }
  
}

回答1:

Your code reflects the basic logic, though there are some syntax flaws. Hopefully this answer will help you understand and adapt that syntax.

  • The code doesn't doesn't take advantage of the Event Objects that are available to onEdit(e), which include the row, column and value of the edited cell. It's not compulsory to use the Event objects, but they certainly make life easier.
  • countRow isn't defined; and because you are working with a spreadsheet of finite length (20 rows); it is probably unnecessary. But it is a sensible idea to allow for bigger spreadsheets. Maybe something like var countRow = sheet.getLastRow(); would be a good alternative Doc Ref.
  • isComplete - we know that this is always on row 20; we also know that it will have a value of "true" or "false". So, you don't need a loop to define this row.
  • At some stage, you may want to "unprotect" a column; say at the start of a new term or year; so it's likely that checking row 20 for a value of "false" could be useful.

Your goal can probably be achieved in many ways. The following should be considered as just one option.

  • The main function is setup in an onEdit(e) simple trigger.
  • I also setup a custom menu (using onOpen) that gives you access to view all the protected columns, and to remove protection if you need to.
  • I've also left some Logger.log statements in the code that may enable you to check the value of certain fields at key stages of the code.
  • All-in-all, this code follows the same logic as your code, but with some more detail.
  • One last thing, this code is designed to work on a specific sheet by virtue of var sheet = ss.getSheetByName(sheetname); but you could just as easily change this to var sheet = SpreadsheetApp.getActiveSheet(); to make it work on multiple sheets in your spreadsheet.

function onEdit(e) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheetname = "Sheet1";
  var sheet = ss.getSheetByName(sheetname);

  // set variable for last column


  //Logger.log(JSON.stringify(e))
  // set variables for edited cells, 
  var edittedRow = e.range.rowStart;
  var edittedColumn = e.range.columnStart;
  var newValue = e.value;
  var headerrange = sheet.getRange(1, edittedColumn);
  var headervalue = headerrange.getDisplayValue();
  //Logger.log("DEBUG: The header range is "+headerrange.getA1Notation()+", and the value is "+headervalue);

  // test if edit row =20, and the checkbox was ticked
  if (edittedRow === 20 && newValue === "TRUE") {
    //Logger.log("DEBUG: The 'ON' leg applies");
    //Logger.log("DEBUG: edittedRow = "+edittedRow+", Editted column = "+edittedColumn+", and value = "+newValue);

    // define the range to protect
    var protectRangeOn = sheet.getRange(1, edittedColumn, 19, 1);
    // protect the range - warning only.
    protectRangeOn.protect().setDescription(headervalue)
      .setWarningOnly(true);
    //Logger.log("DEBUG1: protection set for "+protectRangeOn.getA1Notation());
  }

  //test if edit row=20, and the checkbox was unticked
  if (edittedRow === 20 && newValue === "FALSE") {
    //Logger.log("DEBUG: The 'OFF' leg applies");
    //Logger.log("DEBUG: edittedRow = "+edittedRow+", Editted column = "+edittedColumn+", and value = "+newValue);

    // define the range to unprotect
    var protectRangeOff = sheet.getRange(1, edittedColumn, 19, 1);
    var protections = sheet.getProtections(SpreadsheetApp
      .ProtectionType.RANGE)
    for (var i = 0; i < protections.length; i++) {

      Logger.log("protections range name = " + protections[i]
        .getDescription() + " - Header value = " + headervalue);
      if (protections[i].getDescription() === headervalue) {
        //Logger.log("DEBUG: OFF matches")
        protections[i].remove();
      }
    }
    //Logger.log("DEBUG2: protection unset for "+protectRangeOff.getA1Notation());
  }


}

// Add a custom menu to the active spreadsheet to access Utilities
function onOpen(e) {
  SpreadsheetApp.getUi()
    .createMenu('Protection Utilities')
    .addItem('Show all protections', 'uigetprotections')
    .addItem('Remove all protections', 'removeallprotections')
    .addToUi();
}

function removeallprotections() {
    // remove all protections
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheetname = "Sheet1";
  var sheet = ss.getSheetByName(sheetname);
  var protections = ss.getProtections(SpreadsheetApp.ProtectionType
    .RANGE);
  Logger.log(protections);
  for (var i = 0; i < protections.length; i++) {
    var protection = protections[i];
    Logger.log(protection.getEditors())
    if (protection.canEdit()) {
      protection.remove();
    }
  }
  // Display confirmation dialog
  var ui = SpreadsheetApp.getUi();
  var response = ui.alert('REMOVE ALL PROTECTION',
    'Confirmed: Removed all protections', ui.ButtonSet.OK);
}

function uigetprotections() {
    // generate a list of all RANGE protections
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheetname = "Sheet1";
  var sheet = ss.getSheetByName(sheetname);
  var protections = ss.getProtections(SpreadsheetApp.ProtectionType
    .RANGE);
  //Logger.log(protections);
  var ui = SpreadsheetApp.getUi();
  var protectioninfo = "";
  if (protections.length != 0) {
    for (var p = 0; p < protections.length; p++) {
      //Logger.log("DEBUG: Date = "+protections[p].getDescription()+", Range = "+protections[p].getRange().getA1Notation());
      protectioninfo = protectioninfo + "Date: " + protections[p]
        .getDescription() + ", Range = " + protections[p].getRange()
        .getA1Notation() + "\n";
    }
    var response = ui.alert('SHOW ALL PROTECTIONS', protectioninfo, ui
      .ButtonSet.OK);
  } else {
    var response = ui.alert('SHOW ALL PROTECTIONS',
      "There were no protected ranges", ui.ButtonSet.OK);
  }
}