Running a script by checking a checkbox on two different sheets - google-apps-script

I'm having odd behavior on my code.
I need the script to trigger when I'm using an Ipad or a mobile phone.
I was able to have it work on one sheet "Existing client". Now I'm trying to have a second sheet "new client" that also has the same behavior but triggers others functions.
The thing is it looks like when I switch between sheets, the checkbox needs to be checked multiple times and does not trigger all the time. My solution would be to simply make another spreadsheet for the second sheet "new client" but I would still like to understand what is wrong with what I did?
Here is the code:
So I reduce the code to a minimum, meaning if i check the box, I have the time stamp in a cell. If I have two sheets, it is not working.
Thanks for your help,
j.
function onEditTriggerClientExistant() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Client existant");
var range = sheet.getActiveRange()
if (range.isChecked()) {
if (range.getA1Notation() == "B4") {
sheet.getRange('C4').setValue(new Date());
range.uncheck();
} else {
range.uncheck()
}
}
}
function onEditTriggerNouveauClient() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Nouveau Client");
var range = sheet.getActiveRange()
if (range.isChecked()) {
if (range.getA1Notation() == "A4") {
sheet.getRange('B4').setValue(new Date());
range.uncheck();
} else {
range.uncheck()
}
}
}

var ss = SpreadsheetApp.getActiveSpreadsheet()
function onEdit(e) {
let oldValue = e.oldValue;
let newValue = e.value;
var r = e.range.getRow()
var c = e.range.getColumn()
var active_sheet = ss.getActiveSheet()
var sheetName = active_sheet.getName();
if(sheetName=="sheet1" && r==4 && c==2){
}
else if(sheetName=="sheet2" && r==4 && c==1){
}
}

Related

Get onEdit to trigger from a single cell change

I am trying to run a Google App script that unhides columns, and then rehides columns based whether the cell reference says Blank or not. This is determined by a drop down in a single cell. I got the script to run fine (if a little clunky) whenever any edit is made, but when I try to add the specification of cell it flags an error with the range.
I'm very new to this so I'm a bit out of my depth so any help is appreciated!
function onEdit(e) {
if (e.range.getA1Notation() === 'B2') {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActive().getSheetByName("Group M0 loot");
sheet.showColumns(9, 35);
var range = sheet.getRange("4:4");
var num_cols = range.getNumColumns();
for (var i = 9; i <= num_cols; i++) {
var value = sheet.getRange(4,i).getValue();
if (value == "Blank") {
sheet.hideColumns(i);
};
}
}
}
Try this:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == "Group M0 loot" && e.range.columnStart == 2 && e.range.rowStart == 2) {
sh.showColumns(9, 35);
sh.getRange(4,1,1,sh.getLastColumn()).getValues().flat().forEach((c,i) => {
if(!c) {
sh.hideColumns(i + 1);
}
});
}
}

Apps Script onEdit to add/clear timestamp across multiple sheets if a checkbox is checked/unchecked

I've got the script below working except for the bottom portion starting at //3. The initial portion works on my first sheet listed and adds a timestamp if a checkbox is checked, clears it if it is unchecked. However, it only works on the first sheet, and I need it to work on the second sheet listed as well. The data is set up differently on each sheet so that's why I have these broken out. I'd appreciate any guidance, I'm very new to Apps Script and learning so I'm sure it's a novice and silly mistake:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSheet();
var r = ss.getActiveCell();
//1.Change 'Sheet1' to match your sheet name
if (r.getColumn() == 1 && ss.getName()=='Sheet1') { // 2. If Edit is done in column 1 make change in column 4(D) then:
var celladdress ='D'+ r.getRowIndex();
if(r.getValue() !="" && r.getValue() !=" "){
ss.getRange(celladdress).setValue(new Date()).setNumberFormat("MM/DD/YYYY hh:mm:ss");
} else{
ss.getRange(celladdress).clearContent();
}
//3.Change 'Sheet2' to to match your sheet name
if (r.getColumn() == 1 && ss.getName()=='Sheet2') { // 4. If Edit is done in column (G) then:
var celladdress ='G'+ r.getRowIndex();
if(r.getValue() !="" && r.getValue() !=" "){
ss.getRange(celladdress).setValue(new Date()).setNumberFormat("MM/DD/YYYY hh:mm:ss");
} else{
ss.getRange(celladdress).clearContent();
}
}
}
}
Modification points:
In your script, I thought that an object for searching the sheet name might be able to be used.
In this modification var obj = {Sheet1: "D", Sheet2: "G"} is used.
For example, obj["Sheet1"] returns D. This is used for the modified script.
About the checkbox, you can also use isChecked() for checking whether the checkbox is checked.
When above points are reflected to your script, it becomes as follows.
Modified script:
function onEdit(e) {
var r = e.range;
var ss = r.getSheet();
// Prepare an object for searching sheet name.
var obj = {Sheet1: "D", Sheet2: "G"};
// Using the object, check the sheet and put or clear the range.
if (r.getColumn() == 1 && obj[ss.getSheetName()]) {
var celladdress = obj[ss.getName()] + r.getRowIndex();
if (r.isChecked()) {
ss.getRange(celladdress).setValue(new Date()).setNumberFormat("MM/DD/YYYY hh:mm:ss");
} else {
ss.getRange(celladdress).clearContent();
}
}
}
In this case, the event object is used. But if you want to directly run the function at the script editor, please modify as follows.
From
var r = e.range;
var ss = r.getSheet();
To
var ss = SpreadsheetApp.getActiveSheet();
var r = ss.getActiveCell();
References:
Event Objects
isChecked()

How to copy all data from source sheet to destination sheet?

I've made a Google Sheet that serves to keep track of lot numbers within a manufacturing setting. Right now, when the onEdit trigger is enabled, the data from the source sheet only doubles first row of data in the destination sheet. Here's the link to the Sheet. This is the code I have so far:
function onEdit(e) {
if (e.range.getA1Notation() == 'N2') {
if (/^\w+$/.test(e.value)) {
eval(e.value)();
e.range.clear();
}
}
}
function Reset() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Input" ) {
var dataRange = s.getRange('A5:V14');
var values = dataRange.clearContent();
s.getRange("C5:C14").setValue('-');
s.getRange("F5:F14").setValue('-');
s.getRange("I5:I14").setValue('-');
s.getRange("L5:L14").setValue('-');
}
}
function Submit() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Input');
const targetSheet = ss.getSheetByName('Database');
const data = sh.getRange(5,1,1,23).getValues(); // A5:W14
targetSheet.getRange(targetSheet.getLastRow()+1,3,data.length,data[0].length).setValues(data);
}
If I understand your question correctly you are worried that when you select Submit, there is a double insert of data into the Database sheet.
It can be assumed that this is due to the Submit function being run twice. The first time when checking /^\w+$/.test(e.value) and the second time directly when you run eval(e.value)().
I'm not sure if this is a bug or a feature :-)
Try this code, it works:
function onEdit(e) {
if (e.range.getA1Notation() == 'N2') {
var val = e.value;
switch(val) {
case 'Reset': Reset();
break;
case 'Submit': Submit();
break;
}
e.range.clear();
}
}
Upd.
The double insertion is due to the fact that you are using 2 onEdit() triggers. Have a look at Edith / Triggers of the current project. Delete it.
Upd2.
If you want only filled rows out of 10 to appear on the Database sheet then use this code. It filters the rows based on whether there is some text in column H, such as Adult or Pediatric.
function Submit() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName('Input');
var targetSheet = ss.getSheetByName('Database');
var data = sh.getRange(5,1,10,23).getValues();
Logger.log(data);
var fData = data.filter(data => (data[13] != ""));
Logger.log(fData);
targetSheet.getRange(targetSheet.getLastRow()+1,3,fData.length,fData[0].length).setValues(fData);
}

Cannot get getColumn and getRow methods to return any values

I am new to Google apps script (and javascript for that matter).
In the code below I keep getting "No logs found. Use Logger API to add logs to your project.", tried adding an "event" variable to the onEdit() trigger with no avail.
function onEdit() {
var test = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("test");
var activeCell = test.getActiveCell();
var col = activeCell.getColumn();
var row = activeCell.getRow();
Logger.Log(col);
Logger.Log(row);
if(col == 1 && row == 1) {
var testVar = 1;
Logger.log(testVar);
}
}
Thanks.
You can play around with this to learn more about the event object. It really has a lot of information in it right of out the box.
function onEdit(e) {
if(e.range.getSheet().getName()!='test'){return;}//keeps other pages from affecting the performance of the onEdit function
var activeCell = e.range;//typically e.range is one cell
var col = e.range.columnStart;//there's also a columnEnd
var row = e.range.rowStart;//there's also a rowEnd
Logger.log(JSON.stringify(e));//take a look at this and see what else is there
Logger.Log(col);
Logger.Log(row);
if(col == 1 && row == 1 && e.range.getSheet().getName()=='test') {
var testVar = 1;
Logger.log(testVar);
}
}

Google Apps Script - Make onEdit() recognize setValue() changes

I have a Spreadsheet with some functions. One of them is a onEdit(event) function that copies some values to other sheets based on conditions. This is the code (simplified but with the important parts intact):
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.range;
if(s.getName() === "Lista" && r.getColumn() === 9 && r.getValue() === "Posicionada") {
var sheetname = s.getRange(r.getRow(),3).getValue();
var columnRef = s.getRange(r.getRow(),4).getValue();
var row = s.getRange(r.getRow(),5).getValue();
var targetSheet = ss.getSheetByName("Mapa " + sheetname);
var headers = targetSheet.getRange(1, 1, 1, targetSheet.getLastColumn());
for (var i = 0; i < headers; i++) {
if (headers[i] === columnRef) {
break;
}
}
var column;
if (columnRef === "A1") {
column = 2;
}
else if (columnRef === "A2") {
column = 3;
}
else if (columnRef === "B1") {
column = 4;
}
else if (columnRef === "B2") {
column = 5;
}
if (sheetname === "N2") {
row = row - 30;
}
if (sheetname === "N3") {
column = column - 10;
row = row - 42;
}
targetSheet.getRange(row,column).setValue(s.getRange(r.getRow(), 1, 1, 1).getValue());
}
}
The code works as it should when I manually edit the cell. But, I have a code that edit the cell when the user press a button in a sidebar, this is the code:
function positionMU(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().activate();
var cellLevel = cell.offset(0,2);
var cellLetter = cell.offset(0,3);
var cellNumber = cell.offset(0,4);
var cellStatus = cell.offset(0,8);
var dbq = "Posicionada";
var fora = "Pendente de recebimento";
if (cellStatus.getValue() == "Aguardando posicionamento"){
cellStatus.setValue(dbq); //attention in this line
}
else if (cellStatus.getValue() == "Aguardando saĆ­da"){
cellStatus.setValue(fora);
var cellExitDate = cell.offset(0,6);
cellExitDate.setValue(getDate());
}
}
As you can see, this function change the cell content with setValue(), but, when I use this function, the value of the cell changes, but the onEdit() trigger doesn't work.
How can I make the onEdit() trigger recognize changes made with setValue()?
You are right. onEdit() only triggers if the range is edited manually. As can be seen here, onEdit() triggers when a value is changed by the user.
I tested the function by making function to insert values into a column for which my onEdit responds and nothing happens. Including various other techniques that I could think of. Best thing to do here is to suggest this as an enhancement on App Script's Issue Tracker.
However, I made it work by writing another function to be called when another function in the script makes changes to the sheet. These are the test functions I wrote:
function addValues()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var book = "Book";
var cancel = "Cancel";
var maxRow = range.getLastRow()+1;
for(var i=0; i<4; i++)
{
if (i%2 == 0)
{
sheet.getRange(maxRow, 1).setValue(book);
autoChanges(maxRow);
}else{
sheet.getRange(maxRow, 1).setValue(cancel);
autoChanges(maxRow);
}
maxRow++;
}
}
autoChanges function:
function autoChanges(row)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var data = range.getValues();
var response = "";
sheet.getRange(row, 2).protect();
response = data[row-1][0];
if (response == "Book")
{
sheet.getRange(row, 2).canEdit();
}else{
sheet.getRange(row, 2).setValue("--NA--");
}
}
Not the most elegant solution but this seems to be the only workaround for what you are trying to do.
There are some very good reasons why calling range.setValue() doesn't trigger the onEdit event, and most of them have to do with infinite recursion. In fact, you call setValue() yourself WITHIN onEdit(). This would trigger a recursive call, and from what I can see, you have no provision for handling the base case and thus your code would explode if setValue() did what you want.
Why not simply take all of your code out of your event handler, and put it into another function:
function onEdit (e) {
return handleEdits(e.range);
}
function handleEdits(r) {
s = r.getSheet();
ss = s.getParent();
//the rest of your code should drop right in.
}
then, inside your autoChanges function, go ahead and call handleEdits, passing it an appropriate range, after your call to setValue().
If you like to play with fire, and I personally do, you can call the onEdit(e) function after you make a change. Just send in an object whatever is called and used by the e object.
For me, I just needed to add:
var e={};
e.range=the range you are making a change to in the script;
e.source = SpreadsheetApp.getActiveSpreadsheet();//or make sure you have the sheet for wherever you are setting the value
e.value=whatever value you are setting
e.oldValue=if you onEdit needs this, set it here
//if you are using any of the other standard or special properties called by your onEdit...just add them before calling the function.
onEdit(e);//call the function and give it what it needs.