简体   繁体   中英

Lock Google Sheet tabs in place

Is it possible to give users edit access to a google sheet, but prevent them from changing the order of the sheet tabs at the bottom?

regards

You cannot prevent sheets from being reordered by editors, but you can certainly reorder them back. If one reviews the available Spreadsheet events , one might think that the "on change" event will fire for re-ordered sheets. As of Jan 2019, this is not true. However, you can still bind multiple events (ie "change", "edit", and "open") with an installed trigger, and enforce your desired sheet ordering through the use of either the Spreadsheet Service or the advanced service Sheets , ie the Sheets REST API .

The most efficient reordering is done with the Sheets API without modifying the users' active sheets, but it has a UI refresh bug if you reorder more than a single sheet per API call (the reordering occurs on Google's end, and the browser UI(s) are not updated). This reordering can be done in an average of ~100-230 ms per API call.

Here is example code that is not the most API-efficient, in order to be simpler to understand and implement:

function enforceOrder(eventObject) {
  const requiredSheetOrder = ['name of first sheet', 'name of second sheet' ....];
  // Get the workbook ID for the Sheets REST API.
  const id = (eventObject ? eventObject.source : SpreadsheetApp.getActive()).getId();
  // You must enable the advanced service prior to using this code.
  // https://developers.google.com/apps-script/guides/services/advanced#enabling_advanced_services
  const state = Sheets.Spreadsheets.get(id, {fields: "sheets/properties(title,sheetId,index)"});

  // Collect the requests to be made.
  const batchRequests = [];
  requiredSheetOrder.forEach(function (title, i) {
    var rq = {
      fields: "index",
      properties: { index: i }
    };
    var matched = state.sheets.filter(function (s) { return s.properties.title === title; })[0];
    if (matched)
    {
      rq.properties.sheetId = matched.properties.sheetId;
      // If any preceding sheets are being reordered, or this sheet
      // is not in the right position, we must set this sheet's index.
      if (batchRequests.length || i !== matched.properties.index)
        batchRequests.push({ updateSheetProperties: rq });
    }
    else
      console.warn("No sheet found with required name '" + title + "'");
  });

  // Send updates, if there were any to send.
  if (batchRequests.length)
  {
    // Sheets.Spreadsheets.batchUpdate({ requests: batchRequests }, id);
    // The above wholly-batch line induces the mentioned UI bug.
    // The below one-by-one update does not:
    batchRequests.forEach(function (r) {
      Sheets.Spreadsheets.batchUpdate({ requests: [r] }, id);
    });
    console.log("Reordered " + batchRequests.length + " sheets");
  }
  else
    console.log({message: "No-op", desired: requiredSheetOrder, current: state.sheets });
}

API efficiency can be improved by comparing the current sheet state and the desired outcome state, and computing the minimum number of index specifications to fix the sheet ordering (that is, taking into account that placing a sheet at index i moves the sheet currently at index i to i+1 ).

PS: When working with the Spreadsheet Service, the position / spreadsheet index of a sheet is 1-based. When working with the advanced service / REST API, the sheet's position index is always 0-base.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM