简体   繁体   中英

Google Sheets move cursor onEdit trigger based on cell content

I am trying to write a Google Sheets Apps Script function that checks the content of the current active cell, matches it to the content of another cell, then moves the cursor according to the result of that check.

For a spreadsheet as this example one: https://docs.google.com/spreadsheets/d/1kpuVT1ZkK0iOSy_nGNPxvXPTFJrX-0JgNmEev6U--5c/edit#gid=0

I would like the user to go to D2, enter a value followed by Tab, then while the active cell is in E2, the function will check if the value in D2 is the same in B2. If it is, stays in E2. Then we enter the value in E2 followed by Tab, the function checks if it's the same as C2, if it is, then moves from F2 down and left twice to D3. So if all the values are entered correctly, the cursor zig-zags between the cells in D, E and F as shown below:

在此输入图像描述

The closest I could find is the answer to the one below, but it involves clicking on a method in the menu each time:

Move sheet rows on based on their value in a given column

I imagine the function could be triggered at the beginning of editing the document, then it keeps moving the cursor until the document is completed, at which point the function can be stopped.

Any ideas?

EDIT: what I've tried so far:

I have managed to change the position to a hard-coded position 'D3' and to create a function that moves one down with these functions:

function onOpen() {
  var m = SpreadsheetApp.getUi().createMenu('Move');
  m.addItem('Move to D3', 'move').addToUi();
  m.addItem('Move to one below', 'move2').addToUi();
  m.addItem('Move down left', 'move_down_left').addToUi();
}

function move() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var s = ss.getActiveSheet();
  var range = s.getRange('D3');
  s.setActiveRange(range);  
}

function move2() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var s = ss.getActiveSheet();
  var r = s.getActiveRange();
  var c = r.getCell(1,1);
  var target = s.getRange(c.getRow() + 1, c.getColumn());
  s.setActiveRange(target);
}

function move_down_left() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var s = ss.getActiveSheet();
  var r = s.getActiveRange();
  var c0 = r.getCell(1,1);
  var r1 = s.getRange(c0.getRow(), c0.getColumn() - 1);
  var c1 = r1.getCell(1,1);
  var r2 = s.getRange(c1.getRow(), c1.getColumn() - 2);
  var c2 = r2.getCell(1,1);
  if (c1.getValue() == c2.getValue()) {
    var target = s.getRange(c1.getRow() + 1, c1.getColumn() - 1);
    s.setActiveRange(target);
  }
}

As I mentioned in my comment, you want to use a simple trigger function (so that it works for all users without requiring them to first authorize the script). There are naturally some limitations of simple triggers , but for the workflow you describe, they do not apply.

A key principle of a function receiving the on edit trigger invocation is that it has an event object with data about the cell(s) that were edited:

  • authMode : A value from the ScriptApp.AuthMode enum.
  • oldValue : Cell value prior to the edit, if any. Only available if the edited range is a single cell. Will be undefined if the cell had no previous content.
  • range : A Range object, representing the cell or range of cells that were edited.
  • source : A Spreadsheet object, representing the Google Sheets file to which the script is bound.
  • triggerUid : ID of trigger that produced this event (installable triggers only).
  • user : A User object, representing the active user, if available (depending on a complex set of security restrictions ).
  • value : New cell value after the edit. Only available if the edited range is a single cell.

Of these, we will use range and value . I will leave the business case of handling edits to multiple-cell ranges to you. Stack Overflow is, after all, not where you obtain turnkey solutions ;)

function onEdit(e) {
  if (!e) throw new Error("You ran this from the script editor");
  const edited = e.range;
  if (edited.getNumRows() > 1 || edited.getNumColumns() > 1)
    return; // multicell edit logic not included.

  const sheet = edited.getSheet();
  if (sheet.getName() !== "your workflow sheet name")
    return;

  // If the user edited a specific column, check if the value matches that
  // in a different, specific column.
  const col = edited.getColumn(),
      advanceRightColumn = 5,
      rightwardsCheckColumn = 2;
  if (col === advanceRightColumn) {
    var checkedValue = edited.offset(0, rightwardsCheckColumn - col, 1, 1).getValue();
    if (checkedValue == e.value) // Strict equality may fail for numbers due to float vs int
      edited.offset(0, 1, 1, 1).activate();
    else
      edited.activate();
    return;
  }

  const endOfEntryColumn = 8,
      endCheckColumn = 3,
      startOfEntryColumn = 4;
  if (col === endOfEntryColumn) {
    var checkedValue = edited.offset(0, endCheckColumn - col, 1, 1).getValue();
    if (checkedValue == e.value)
      edited.offset(1, startOfEntryColumn - col, 1, 1).activate();
    else
      edited.activate();
    return;
  }
}

As you digest the above, you'll note that you are required to supply certain values that are particular to your own workflow, such as a sheet name, and the proper columns. The above can be modified in a fairly straightforward manner to advance rightward if the edited column is one of several columns, using either a constant offset to the respective "check" column, or an array of respectively-ordered offsets / target columns. (Such a modification would almost certainly require the use of Array#indexOf .)

A caveat I note is that strict equality === fails if your edits are numbers representable as integers, because Google Sheets will store the number as a float. Strict equality precludes type conversion by definition, and no int can ever be the exact same as a float . Thus, the generic equality == is used. The above code will not equate a blank check cell and the result of deleting content.

Method references:

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