Script Editor Error: Not moving row based on specific value - google-apps-script

I am trying to move a row of data from one sheet to another, when a specific value is recorded in a specific column.
I have found and adapted the following code to use in the Apps Script:
function onEdit(event) {
// assumes source data in sheet named Responses
// target sheet of move to named Completed
// test column with yes/no is col Y or 25
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Responses" && r.getColumn() == 25 && r.getValue() == "yes") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Completed");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
I have tested this on a copy of this data and it has worked fine. However, when using the original, nothing happens, when yes is entered in column Y. I have listed below some reasons why I think this may be occurring:
This is a shared sheet, I am not the owner. The owner has granted permissions
The responses sheet is connected with a Google Form
P.S. The following error appears when the script is executed from the editor, I don't believe this is an issue based on the type of trigger, it also appeared on my test and had no impact
TypeError: Cannot read property 'source' of undefined
onEdit # Code.gs:6
I would appreciate any suggestions on workarounds!

In order to help you to debug your script, just after function onEdit(event) { add a the following line:
console.log(JSON.stringify(event,null,' '));
The above will print the event object "printable" properties on the execution logs. This will allow you to validate, first, that the function is actually triggered when the spreadsheet is edited by using the Google Sheets UI, second, the coordinates of the edited cell as well the value entered into edited cell.
The coordinates will be shown as properties rowStart, columnStart, rowEnd, columnEnd.
Also you might find helpful to add the following line before the if statement.
console.log(s.getName());
NOTE: The error "Cannot read property 'source' of undefined" occurs when the onEdit function is run from the script editor as the event object is undefined.
Related
How can I test a trigger function in GAS?
How to run a function when specific range is edited

Related

I am wanting to run a function in script apps that automatically looks for a word in a column and automatically archives that row to another tab

I want to automatically have a row archive to another tab if column D contains the word Deprovisioned. I am not manually editing the cell, I am copy and pasting from a CSV export so the columns come pre-filled with information. I tried the below script, but received an error saying undefined. I am not sure if this has something to do with the fact that I am not manually editing anything on the sheet?
Below is the error I get
var s = event.source.getActiveSheet(); undefined.
Below is the script I am using
function onEDIT(event) {
// assumes source data in sheet named Needed
// target sheet of move to named Acquired
// test column with yes/no is col 4 or D
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Copy of Zoominfo Usage" && r.getColumn() == 4 &&
r.getValue() == "DEPROVISIONED") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("ZOOMINFO ARCHIVE");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == "Copy of Zoominfo Usage" && e.range.columnStart == 4 && e.value == "DEPROVISIONED") {
let tsh = e.source.getSheetByName("ZOOMINFO ARCHIVE");
let tgt = tsh.getRange(tsh.getLastRow() + 1, 1);
sh.getRange(e.range.rowStart, 1, 1, sh.getLastColumn()).moveTo(tgt);
sh.deleteRow(e.range.rowStart);
}
}
If you are trying to use simple edit trigger instead of onEDIT you should use onEdit.
An edit trigger, simple or installable will be triggered only when a user uses the Google Sheets UI to edit a cell or range. A paste will trigger the script but the script is not prepared to manage pasting multiple cells
r.getValue() returns only the value of top-left cell
r.getRow() returns only the row of the top row.
It might work when pasting a single row.
It will not work when calling the script from the script editor, as the function requires the event parameter, which is provide automatically when the function is called by the trigger but not when it's called form the script editor.
Please bear in in mind that the active sheet and active range will be the range that has being edited by the user using the Google Sheets UI. When running the function from the script editor, if the Google Apps Script project is opened from the bounded spreadsheet they will be the sheet / range that are active for the user running the function, but if Google Apps Script project were opened from other means like the https://script.google.com then the the methods calling the active sheet / range might return the first sheet / first cell or throw an error.
References
https://developers.google.com/apps-script/guides/triggers
Related
Is it possible to trigger onEdit function on formula
How can I test a trigger function in GAS?

Auto Move Google Form Response by ticking check box

I have google Form. User fills google form and a sheet with name "Form Response" is created to record user responses. I would like to use script to move data if I tick mark in W column, from "Form Response" sheet to "Verified Form Responses".
Link of the form Response Sheet is
https://docs.google.com/spreadsheets/d/1LUUEZ7sSjBy-WWL3TZt8l6sqtrEBn3dZ03iRDTY1bF0/edit?usp=sharing
The script I am using is :
function onEdit(event) {
// assumes source data in sheet named Needed
// target sheet of move to named Acquired
// test column with yes/no is col 23 or W
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Form responses 1" && r.getColumn() == 23 && r.getValue() == true) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Verified Form Responses");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
}
}
This code is not working. Please help.
Issue:
For some reason the script is detecting content in all 1000 rows from Verified Form Responses sheet.
This can be checked by logging targetSheet.getDataRange().getA1Notation(): the logged notation is A1:Z1000, which means the script is seeing some content in row 1000. It can also be checked by using appendRow(rowContents): the provided data is appended to row 1001, not to the first row with supposedly no content. Things like deleting all values from these rows don't cause any change (the script still considers these rows to have content).
I'm unsure what's the reason for that, since I don't see any array formula that might be messing with that. But every new row that is added to the sheet is interpreted as having content.
In any case, since it's detecting content in row 1000 (the last one in the sheet), getLastRow() + 1 (that is, row 1001) is outside the dimensions of the sheet, so this error message appears:
The coordinates of the target range are outside the dimensions of the sheet.
Solutions:
Fortunately, you have many options to solve this issue. Choose the one you prefer:
Create a new target sheet, and send your data there instead of sending it to Verified Form Responses.
Remove all the supposedly empty rows from Verified Form Responses (that is, A42:Z1000) and use appendRow instead of copyTo (formatting will not be copied):
var targetSheet = ss.getSheetByName("Verified Form Responses");
targetSheet.appendRow(s.getRange(row, 1, 1, numColumns).getValues()[0]);
Find the actual first row without content by applying getDataRange() and filtering out rows for which all cells are empty (only works if there are no in-between empty rows):
var targetSheet = ss.getSheetByName("Verified Form Responses");
var realLastRow = targetSheet.getDataRange().getValues()
.filter(row => row.join('') != "").length;
var target = targetSheet.getRange(realLastRow + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);

Error only appears when running script in Apps Script Editor

I am trying to run a script that auto-populates the date in column F whenever data is entered or changed in column E in a spreadsheet with multiple sheets.
I currently have a script which was written for me based on what I described but I was getting an error code. I went back to my original question and explained that this script was needed to run on a single sheet within a spreadsheet with multiple sheets. He gave me some additional information but this was his last answer "yes, you will need to replace event.source.getActiveSheet() with something like "getsheetbyname". I have tried everything that is within my limited knowledge to work with what he gave me but I am still getting an error code no matter what I try.
Here is the area that is giving me the error.
var sheet = event.source.getsheetbyname();
Here is the error code I am receiving
TypeError: Cannot read property "source" from undefined. (line 2, file "Code")
I am aware that there needs to be the name of the sheet I am wanting the script to run on but I do not know how to code it to do so. The name of the sheet is "Juvenile weights"
The expected results should be when I add or change the data in column E it should auto-populate the current date into the adjacent cell in the adjacent column.
When I save the script and then run the script to make sure it's working, of course, it gives me the error code I described above. Then when I go back to that sheet after saving the script instead of auto-populating the date, now when I highlight a string of cells in a row it changes all the following cells to the same information I have in the first cell I started highlighting. Very odd!
The script + error code:
The code:
function onEdit(event) {
var sheet = event.source.getActiveSheet();
// note: actRng = the cell being updated
var actRng = event.source.getActiveRange();
var index = actRng.getRowIndex();
var cindex = actRng.getColumnIndex();
if (cindex == 5) { // 1 == Column A, 2 == Column B, 3 == Column C, etc.
var dateCol = sheet.getLastColumn();
var lastCell = sheet.getRange(index,dateCol);
var date = Utilities.formatDate(new Date(), "EST", "MMM-dd-yyyy");
lastCell.setValue("'" + date);
}
}
I believe this does the same thing:
function onEdit(e) {
var sheet = e.range.getSheet();
if (e.range.columnStart == 5) {
sheet.getRange(e.range.rowStart,sheet.getLastColumn()).setValue("'" + Utilities.formatDate(new Date(), "EST", "MMM-dd-yyyy HH:mm:ss"));
}
}
Is there a reason you aren't using SpreadsheetApp.getActiveSheet().getSheetByName("Juvenile weights");

Script to move entire row to a new tab and then selected columns to a different doc

I have the following script running on a document (I found on the forum and unfortunately I cannot remember who it was to give credit to but it works great), pulling the whole rows data into a new sheet then deleting the row from its current location;
function onEdit(event)
{
// assumes source data in sheet named Schedule
// target sheet of move to named Invoiced
// test column with "9 - Invoiced" is col 1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "AllOpps" && r.getColumn() == 1 && r.getValue() ==
"Outreached")
{
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("InitialOutreach");
if(targetSheet.getLastRow()+1 == targetSheet.getMaxRows())
{
targetSheet.insertRowsAfter(targetSheet.getLastRow(), 5);
//inserts 5 rows after last used row
}
var target = targetSheet.getRange(targetSheet.getLastRow()+1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
What I am looking for is an amendment to this and I have no idea how to make it work as my script knowledge is extremely limited, in fact, I am not even sure if it is possible but here goes.
Upon selection of "Outreached" I would like that row to do 2 things, firstly for the whole row to be copied across to the InitialOutreach tab, as it does now, and at the same time column 11,12,13 and 14 to be copied into a completely different document, for ease of use I have added it in the shared sample doc as Mail. This second copy will need to be into the respectively named columns
You can find a sample sheet here. Please, note that AllOpps and Initial Outreach are in the same document and represents the initial transfer while Mail Merge tab will be the second transfer. Once again the second transfer ie. only select columns will be in a completely different document.
https://docs.google.com/spreadsheets/d/1x_NFLXC2doWAgCWcAbxpuAh1vW-IclMZ1prN4loWdDA/edit?usp=sharing.
Once again I am not even sure running 2 different tasks on 1 trigger is even possible.
NOTE: This reply has been modified from previous versions, to deal with various changes and problems as reported by the OP.
The code below should do what you need. Note carefully the changed function name myOnEdit which also appears in the onOpen event, where it is named as an "installable" trigger. See later notes on reason for this.
function onOpen() {
ScriptApp.newTrigger('myOnEdit')
.onEdit()
.create();
}
function myOnEdit(event)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "AllOpps" && r.getColumn() == 1 && r.getValue() == "Outreached")
{
var row = r.getRow();
var numColumns = s.getLastColumn();
// first copy and paste the "Outreached" row in entrity
var targetSheet = ss.getSheetByName("InitialOutreach");
if(targetSheet.getLastRow()+1 == targetSheet.getMaxRows())
{
targetSheet.insertRowsAfter(targetSheet.getLastRow(), 5);
//inserts 5 rows after last used row
}
var target = targetSheet.getRange(targetSheet.getLastRow()+1, 1);
var values = s.getRange(row, 11, 1, 5).getValues(); // save the values to copy to "mail Merge"
s.getRange(row, 1, 1, numColumns).moveTo(target);
Logger.log(values);
// Copy the required columns to "Mail Merge" spreadsheet"
var mailMergeSS= SpreadsheetApp.openById('--copy your sheet ID here--');
targetSheet = mailMergeSS.getSheetByName("Mail Merge");
if(targetSheet.getLastRow()+1 == targetSheet.getMaxRows())
{
targetSheet.insertRowsAfter(targetSheet.getLastRow(), 5);
//inserts 5 rows after last used row
}
target = targetSheet.getRange(targetSheet.getLastRow()+1,1,1,5);
target.setValues(values);
s.deleteRow(row);
}
}
1) Make the new target spreadsheet for the mail merge lines and make a new tag called "Mail Merge". Make
2) To find the ID of the new sheet open it and look at the URL. It should look something like this:
https://docs.google.com/spreadsheets/d/14NP6TUyj1xLCPjKsPdGS6fiO0Bvzv1u4696LFd3tA7I/edit#gid=0
The ID is the emboldened bit ie 14NP6TUyj1xLCPjKsPdGS6fiO0Bvzv1u4696LFd3tA7I in the example above,. Yours will be different, so copy and paste it so that your code line looks like:
var mailMergeSS= SpreadsheetApp.openById('14NP6TUyj1xLCPjKsPdGS6fiO0Bvzv1u4696LFd3tA7I');
To avoid this error:
SpreadsheetApp.openById([0AjqSnE_p3nFqdDN0LWpFbjFqVDRwNmFGOV91QzZrZc])
[0 seconds] Execution failed: You do not have permission to perform
that action.
.. which arises when you try to open an external sheet, you need to use "Installable Triggers". The appropriate references are here:
www.developers.google.com/apps-script/guides/triggers/installable
developers.google.com/apps-script/guides/triggers/events
Installable triggers can be installed in 2 ways:
In your CopyCols sheet, go to the script editor and select Current
Project Triggers. Add a new trigger with settings as follows: Choose
which function to run: myOnEdit Which runs at deployment:
head Select Event Source: from Spreadsheet Select
event type: onEdit Then save and restart your sheet..
or....In your code add this function lines:
function onOpen() {
ScriptApp.newTrigger('myOnEdit')
.onEdit()
.create();
}

Move entire row to another sheet using time based action rather than onEdit

I am using the following code to move an entire row of data from one sheet to another, which works perfectly.
I am using AppSheet for users to access and edit the data which blocks the onEdit function in Sheets. AppSheet have suggested that I change this script to a "time based trigger" so that edits within the app have the same action as editing the column directly in "Sheets"
Is there a way to easily do this?
Thank you in advanced!
function onEdit(event) {
// assumes source data in sheet named Needed
// target sheet of move to named Acquired
// test column with yes/no is col 4 or D
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Stock" && r.getColumn() == 14 && r.getValue() == "Booked") {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Bookings");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
As you can see the function name is onEdit() which means it's an edit trigger based function. In other words, it's supposed to get triggered and executed in each edit.
But now you want it to be based on time and not on edit. So you can rename the function and create a time based trigger from top menu for this function.
Steps :
Rename onEdit() function. Maybe you can rename it to moveRow()
Select a time based trigger from top menu bar.
Choose suitable schedule and this function from drop down.
Save the changes.
Make sure you have given appropriate permissions. You can check this by trying to run the function once manually(By selecting it from top Select function drop down and clicking run/execute icon).