I am using Gdocs spreadsheet for jobs queue.
I would like to know how a row and all its content (from column A:AS) can be moved from "Live WIP Jobs" (sheet1) Tab to "Delivered Jobs" (Sheet2) Tab by marking it as "Delivered" in Column "AP".
Normally it will be marked as WIP in sheet1.
On marking it as Delivered, I would like the row to copied to the Sheet2 and get it removed from sheet1.
Attaching sheet for reference
https://docs.google.com/spreadsheets/d/1gZYni8SGUa4Ohu3BIOxJh2bQSUqQh_5Q3epDidP574E/edit#gid=1557156093
I also tried the below script.. but it wasn't working and fetching error:
function CopyRowsOnConditions() {
// assumes source data in sheet named Live WIP Jobs
// target sheet of move to named Delivered
// test column with Delivered/WIP is col AP or 42
var sheet = SpreadsheetApp.getActiveSheet();
var numRows = sheet.getDataRange().getNumRows();
var source = sheet.getRange(2, 42, numRows);
if(s.getName() == "Live WIP Jobs" && r.getColumn() == 42 && r.getValue() == "Delivered"){
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Delivered");
if(targetSheet.getLastRow() == targetSheet.getMaxRows()) {
targetSheet.insertRowsAfter(targetSheet.getLastRow(), 20); //inserts 20 rows after last used row
}
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
Checking the code in the script (the one you posted was not complete) i noticed that you are creating the variables "r" and "s" using the variable "event".
When you have a event (eg. onEdit) the function receives a parameter event, then you can us it. here is information in those events https://developers.google.com/apps-script/guides/triggers/events
If you are going to use an event, change the code accordingly, as mention in the documentation.
Related
I am trying to use an onEdit trigger when a specific tab in a sheet is edited and copy it over to a specific tab in another sheet. For example: If there is any change in Sheet 1 Test 1 tab then it will copy whatever is in Sheet 1 Test 1 tab onto Sheet 2 Test 1. But if the change is in Sheet 1 Test 2 tab then it will copy whatever is in Sheet 1 Test 2 tab onto Sheet 2 Tab 2 tab.
I am able to do it for manual copy and pasting only(i can successfully copy Sheet 1 Test 1 tab to Sheet 2 Test 1 tab or Sheet 1 Test 2 tab to Sheet 2 Test 2 tab) but when I add the onEdit trigger and if loops on my code(for specifying where the edit happened and where the source and destination tabs will be) then the code doesn't run.
Here are my 2 codes(1st will be the if else loop to specify source and destination and 2nd will be the onEdit trigger):
Code 1
function test1()
{var sheet = SpreadsheetApp.getActiveSheet().getSheetName()
if(sheet == 'Test 1') {
//your script
var sss = SpreadsheetApp.openById('1xk1ayrBYXCDdHcIwi7Hukq1xnNjqSTsQ7CHQbzfFiRM'); //replace with source ID
var ss = sss.getSheetByName('Test 1');
var sr = ss.getRange("A1:N25");
var data = sr.getValues();
var tss = SpreadsheetApp.openById('1Ut-eyO3FMBApQd62ewtINmIQSQJSDL7DCU5bRIzdBVY'); //replace with destination ID
var ts = tss.getSheetByName('Test 1');
var tr = ts.getRange("A1:N25");
tr.setValues(data);
}
else if(sheet == 'Test 2') {
//your script
var sss = SpreadsheetApp.openById('1xk1ayrBYXCDdHcIwi7Hukq1xnNjqSTsQ7CHQbzfFiRM'); //replace with source ID
var ss = sss.getSheetByName('Test 2');
var sr = ss.getRange("A1:N25");
var data = sr.getValues();
var tss = SpreadsheetApp.openById('1Ut-eyO3FMBApQd62ewtINmIQSQJSDL7DCU5bRIzdBVY'); //replace with destination ID
var ts = tss.getSheetByName('Test 2');
var tr = ts.getRange("A1:N25");
tr.setValues(data);
}
}
Code 2
function createEditTrigger() {
ScriptApp.newTrigger("test 1")
.forSpreadsheet(SpreadsheetApp.getActive())
.onEdit()
.create();
}
Here are my sample sheets:
Sample Sheet 1: https://docs.google.com/spreadsheets/d/1xk1ayrBYXCDdHcIwi7Hukq1xnNjqSTsQ7CHQbzfFiRM/edit#gid=0
Sample Sheet 2:
https://docs.google.com/spreadsheets/d/1Ut-eyO3FMBApQd62ewtINmIQSQJSDL7DCU5bRIzdBVY/edit#gid=921178690
What would be the best way to approach this if I only need to copy changes in sheet 1 into sheet 2? I dont need to monitor if any changes happens in sheet 2 nor do I need to copy anything from sheet 2 to sheet 1.
SpreadsheetApp.openById() require authorization and onEdit() cannot perform operations that require permission. You must use an installable trigger.
I already try everthing but I cant make this work =/
I'm trying to copy data from one spreadsheet to other using setValues(), because link doesn't work for me. I also need to keep the trigger on edit.
So, I create one fuction called AddConvocacao, and always when have any change the script run.
function addConvocacao(e){
var linha = e.range.getRow(); //get the number of the line, where have edit
var nome = e.source.getActiveSheet().getRange(linha,2).getValue(); //get the value of the field
var targetSheet = SpreadsheetApp.openById('1iQbZ7iB9ddc-HwLK9vG0eVEeWWqXKJZ0ry7U_Hm4SkQ') //open the other spreedsheet
var targetName = targetSheet.getSheetByName('Pac'); //open the tab
var lastRow = targetName.getLastRow(); //count the last row in this tab
lastRow = lastRow+1; //add 1
targetName.getRange(lastRow, 2).setValue(nome); // set the value
// targetName.getRange(lastRow, 3).setValue(valorCol7);
// targetName.getRange(lastRow, 5).setValue(dose);
// targetName.getRange(lastRow, 6).setValue(diagnostico);
// targetName.getRange(lastRow, 7).setValue(medico);
}
why dosen't work when I use on edit?
Thanks so much! =)
I did it a little different I think. I put checkboxes in column one and capture the value from column 2 and sent it to the other spreadsheet to the bottom of column 2
function onMyEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
//Logger.log(JSON.stringify(e));
if (sh.getName() == 'Sheet1' && e.range.columnStart==1 && e.value=="TRUE") {
//e.source.toast('cond');
const v = sh.getRange(e.range.rowStart, 2).getValue();
var tss = SpreadsheetApp.openById(getGlobal('targetid'));
var tsh = tss.getSheetByName('Sheet1');
tsh.getRange(tsh.getLastRow() + 1, 2).setValue(v);
e.range.setValue("FALSE");
}
}
You must use an installable trigger to us openById();
getGlobal(targetid) just gets a spreadsheet id you can replace that with the id
Also I limited the action to only one sheet and only when I set the checkbox to true. I reset it back to false in the code.
You'll need to modify a few things to get it to work for you because when I'm doing the examples I do it my way.
I'm very new to scripting in Google Sheets so my question may be either a lot more difficult than I think, or much simpler.
Basically, I have a Google Sheet that keeps track of a list of birthdays in one column, as well as what age group that person would belong to -- Child (under 13), Teen (13-17), or Adult (18+) -- in another column. The "Age Group" column is calculated using the following formula:
=IF(DATEDIF(H2, TODAY(), "Y") >= 18, "Adult", IF(DATEDIF(H2, Today(), "Y") >= 13, "Teen", "Child"))
with column H being the Birthday column.
My Google Sheet is set to recalculate the Today() function every hour, regardless of whether the file is open or not, so should a person's 13th or 18th birthday roll around, the Age Group column will update automatically.
My goal is to create a function that sends me an email whenever somebody's Age Group changes from Child to Teen or from Teen to Adult -- without requiring the Google Sheet to be opened by the user, or modified in any way, to trigger.
So far, I've been experimenting with "on edit" triggers, but I've noticed that this requires me to manually change an Age Group cell to trigger -- defeating the purpose of automation.
I've also tried changing my Trigger Event Type from "on edit" to "on change", hoping this would trigger the script whenever a cell in the Age Group column changes its resulting value, but this has not worked so far.
My code currently stands as follows (note that this code only makes a notice pop up rather than sending an actual email -- I haven't yet gotten to that part):
/*
This is the function that is triggered by an edit to
the Google Sheet
*/
function onEdit(e) {
sendEmailOnApproval(e);
}
/*
Primarily used for earlier debugging
*/
function showMessageOnApproval(e)
{
var edited_row = checkStatusIsApproved(e);
if(edited_row > 0)
{
SpreadsheetApp.getUi().alert("Row # "+edited_row+" approved!");
}
}
/*
Determines if the Age Group column reads Teen or Adult.
Column 9 (or 'I' in the sheet) is the Age Group column.
*/
function checkStatusIsApproved(e)
{
var range = e.range;
if(range.getColumn() <= 9 &&
range.getLastColumn() >=9 )
{
var edited_row = range.getRow();
var status = SpreadsheetApp.getActiveSheet().getRange(edited_row,9).getValue();
if(status == 'Adult' || status == 'Teen')
{
return edited_row;
}
}
return 0;
}
function sendEmailOnApproval(e)
{
var approved_row = checkStatusIsApproved(e);
if(approved_row <= 0)
{
return;
}
sendEmailByRow(approved_row);
}
/*
At the moment, this function only creates a little pop-up
box containing the text of the email I would like to send.
*/
function sendEmailByRow(row)
{
var values = SpreadsheetApp.getActiveSheet().getRange(row,1,row,9).getValues();
var row_values = values[0];
var mail = composeApprovedEmail(row_values);
SpreadsheetApp.getUi().alert(" subject is "+mail.subject+"\n message "+mail.message);
}
/*
Writes the email. Column 0 (or 'A') is the first name,
1 (or 'B') is the last name.
*/
function composeApprovedEmail(row_values)
{
var first_name = row_values[0];
var last_name = row_values[1];
var age = row_values[8];
var message = "The following person should be updated on the website: "+first_name+" "+last_name+
" Age Range: "+age;
var subject = "UPDATE WEBSITE for "+first_name+" "+last_name;
return({message:message,subject:subject});
}
While this code works when manually changing the values in the Age Range column, how can I adapt it to catch the automatic updates caused by daily recalculation of the Today() function the column relies on?
According to the Apps Script Trigger documentation:
onOpen(e) runs when a user opens a spreadsheet, document, presentation, or form that the user has permission to edit
onEdit(e) runs when a user changes a value in a spreadsheet
Therefore, what you are trying to do cannot be done by using the method that you were previously using since you were trying to use a trigger which would fire every time a change was made by a function (the Sheets formula) and not by a user.
Workaround
What you can do instead is to:
Use the Sheets formula you were previously using but change the Recalculation settings to On change instead of On change and every hour like you were previously doing.
In this way, you will still get the ages categorized based on the dates provided.
Use the following script:
function ageChanges(){
var ss = SpreadsheetApp.getActive().getActiveSheet();
var dateVals = ss.getRange("YOUR_RANGE_FOR_THE_DATES").getValues();
var ageVals = ss.getRange("YOUR_RANGE_FOR_THE_AGES").getValues();
var dateNow = new Date();
var recipient = "EMAIL_ADDRESS";
var subject = "Age Change in Spreadsheet";
var body = "";
for (var i=0; i<dateVals.length; i++){
var ages = (dateNow - dateVals[i][0])/(3.154e+10);
if (ages > 18 && ageVals[i][0]!="Adult") {
ss.getRange(i+1, 9).setValue("Adult");
body = "Change in column H, row"+i+".";
MailApp.sendEmail(recipient,subject,body);
}
else if (ages > 13 && ages < 18 && ageVals[i][0]!="Teen") {
ss.getRange(i+1, 9).setValue("Teen");
body = "Change in column H, row"+i+".";
MailApp.sendEmail(recipient,subject,body);
}
}
}
The script computes the ages based on the dates you have in your Spreadsheet. If the age does not match with the corresponding category, a mail will be sent with the changes made.
In order to monitor the changes daily you will have to use the above script as an installable trigger.
Create an installable trigger with the following options:
In this way, the script will run every day at the time of the day selected by you (in this case, Midnight to 1am) and if any age changes occur, you will receive the email(s) with the changes.
Furthermore, I suggest you take a look at these links since they might be of help in your future development:
Installable Triggers;
MailApp Class.
I want to create a way to hide a certain number of rows if there is a certain value in a cell of a Google spreadsheet.
E.g.
A B
1 Include All options`? Yes/No
2 Option A: Yes/No
3 Option B: Yes/no
etc.
If cell B1 is "yes" there is no need to look at all other options. However, if they select "No", there needs to be an option for selecting the Option "Yes/No". For this reason, I would like to hide the rows when option = yes but unhide them if it is No
This code detects whether a certain cell (B3) was edited, then hides a couple of rows under that row (row 3) if it was edited:
function onEdit(e) {
Logger.log('e.value: ' + e.value);
var cellEdited = e.range.getA1Notation();
Logger.log('cellEdited: ' + cellEdited);
if (cellEdited === "B3") {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var theSheet = ss.getActiveSheet();
theSheet.hideRows(4, 2);
};
}
This code uses a function name of onEdit(), which means that it monitors the spreadsheet for edits to a cell. If there is an edit, the function runs. This is a "simple" trigger. There are also installable triggers for monitoring the spreadsheet.
Note the Logger.log() statements. These statement print information to the LOGS which you can VIEW from the VIEW, LOGS menu.
For your purposes:
function onEdit(e) {
Logger.log('e.value: ' + e.value);
var cellEdited = e.range.getA1Notation();
Logger.log('cellEdited: ' + cellEdited);
if (cellEdited === "B1" && e.value === "yes") {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var theSheet = ss.getActiveSheet();
theSheet.hideRows(2, 2);
};
}
I am currently using google forms to enable users to submit site changes. This is all working beautifully.
I have added an extra column that has ticket status. Now I have written a script that checks for when this is updated to Done and then moves that row into another sheet entitled done.
However this only works if i update a row that i manually added. If I change the column on a row created from the form entry it will not work. Has anyone seen this issue before. Code is below.
function onEdit(e){
/*
When a user updates a status to done the ticket gets moved to another sheet
*/
var sheetNameToWatch = "Form responses 1"; // The sheet to watch for changes
var columnNumberToWatch = 1; // The column where the change happens on the above sheet
var valueToWatch = "Done"; // What is the text you are looking for
var sheetNameToMoveTheRowTo = "Done"; // The Sheet name for where the row gets moved to.
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet(); // Get the active sheet
var range = sheet.getActiveCell(); // Get the current cell that has just been updated
// Check that you are on the correct sheet and column.
if (sheet.getName() == sheetNameToWatch && range.getColumn() == columnNumberToWatch && range.getValue() == valueToWatch) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo); // get a reference for the target sheet
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1); // get a reference for the target row
sheet.getRange(range.getRow(), 1, 1, sheet.getLastColumn()).moveTo(targetRange); // copy the row from current sheet to the new sheet
sheet.deleteRow(range.getRow()); // Delete the row from the old sheet
}
}
Yep, the onEdit function won't fire unless you do it manually, you'll want to use the onFormSubmit trigger, which will fire when a form response is received. This is a manually installed trigger connected to your form, which should be able to do the function above pretty much as written.
var form = FormApp.openById('1234567890abcdefghijklmnopqrstuvwxyz');
ScriptApp.newTrigger('myFunction')
.forForm(form)
.onFormSubmit()
.create();
To be safe, though, you may want to define your spreadsheet, sheet, and range by id or by name rather than by whether they are active, I believe getActiveWhatever() kinds of methods will return null if the spreadsheet isn't open.
As mentioned, using active is not the best idea.
Instead of:
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Get the active spreadsheet
var sheet = SpreadsheetApp.getActiveSheet(); // Get the active sheet
var range = sheet.getActiveCell(); // Get the current cell that has just been updated
Try:
var range = e.range;
var sheet = range.getSheet();
var ss = sheet.getParent();
If you try this you cannot execute it from the code editor because no event is passed. You must execute it by actually submitting a form.