Run Google appscript on change of dropdonw - google-apps-script

I am very new to Google Appscript and support of this community will really be appreciated. Using different posts on the Stakeoverflow community I had designed an appscript to copy and paste the data from one worksheet to another and this is working fine (the data of worksheet named Copy is paste in worksheet named Paste). I had also created a worksheet named Trigger and in that I had created a dropdown in cell A1, now I want my script to run every time when the dropdonw in this sheet is changed. I had checked the different solutions on this community but as am new to appscirpt could not design a perfect solution to my case. Below is the link to the sheet and my current script.
https://docs.google.com/spreadsheets/d/1xy5eN8_PHXi9RPWK_EKg99dylaDjQ9lcilrSW0GP4B0/edit#gid=0
function Referesh() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
var source = copySheet.getRange(2,1,copySheet.getLastRow(),2);
var rub = copySheet.getRange(2,1,copySheet.getLastRow(),2);
var destination =
pasteSheet.getRange(pasteSheet.getLastRow()+1,2,copySheet.getLastRow(),2);
source.copyTo((destination), {contentsOnly: true});
rub.clearContent();
console.log(pasteSheet.getLastRow());
}
Any help on above will be appreciated.

I believe your goal is as follows.
You want to automatically run your script by changing the dropdown list of the cell "A1" of "Trigger" sheet.
In this case, how about using the OnEdit simple trigger as follows?
Modified script:
Please copy and paste the following script to the script editor of Spreadsheet and save the script. When you use this script, in this case, please change the dropdown list of the cell "A1" of "Trigger" sheet to "Run". By this, the script is run.
function onEdit(e) {
var sheetName = "Trigger";
var runScript = "Run";
var { range, source, value } = e;
var sheet = range.getSheet();
if (sheet.getSheetName() != sheetName || range.columnStart != 1 || range.rowStart != 1 || value != runScript) return;
var ss = source;
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
var source = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var rub = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var destination = pasteSheet.getRange(pasteSheet.getLastRow() + 1, 2, copySheet.getLastRow(), 2);
source.copyTo((destination), { contentsOnly: true });
rub.clearContent();
console.log(pasteSheet.getLastRow());
range.setValue("Refresh"); // By this script, the value of "Run" is changed to "Refresh".
}
Note:
It seems that there are 2 values of Run and Refresh in your dropdown list. Unfortunately, I couldn't know the trigger value. So, in this sample script, when the dropdown list is changed to Run, the script is run by the simple trigger. If you want to change this, please modify the above script.
When you run directly onEdit with the script editor, an error occurs because of no event object. So, please be careful about this.
If you want to ignore the trigger value, I think that the following script might be able to be used. In this case, the dropdown list is changed, the script is run.
function onEdit(e) {
var sheetName = "Trigger";
var { range, source } = e;
var sheet = range.getSheet();
if (sheet.getSheetName() != sheetName || range.columnStart != 1 || range.rowStart != 1) return;
var ss = source;
var copySheet = ss.getSheetByName("Copy");
var pasteSheet = ss.getSheetByName("Paste");
var source = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var rub = copySheet.getRange(2, 1, copySheet.getLastRow(), 2);
var destination = pasteSheet.getRange(pasteSheet.getLastRow() + 1, 2, copySheet.getLastRow(), 2);
source.copyTo((destination), { contentsOnly: true });
rub.clearContent();
console.log(pasteSheet.getLastRow());
}
Reference:
Simple Triggers

Related

Trigger a function when one cell is edited in Google Sheets

after some hours of reading documentation and other answers I couldn't solve my problem.
I'm trying to trigger a formula when one cell is edited. I get it to run when I just ask a value to be set (see commented line in the code) but not when I call another formula.
Here's the script:
function onEdit() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var column = cell.getColumn();
if ( row ===1 && column ===4 && sheet.getName() ==="Hoja 1" ) {
sendData();
//sheet.getRange(1,1).setValue("5");
}
function sendData() {
var sheet = SpreadsheetApp.openById("1pxS9F9YEagzzRyTOqIDGVpDaCEiY_Z1DOYxq1QVzWGk");
var source_sheet = sheet.getSheetByName("Hoja 1");
var target_sheet = sheet.getSheetByName("Hoja 2");
var range1 = source_sheet.getRange(1, 7, 6, 1).getValues();
target_sheet.getRange(1,1,6,1).setValues(range1);
}
}
You have to pass the sheet into the called function this way:
sendData(spreadsheet);
function sendData(sheet) {
...
}
onEdit() is a simple trigger. Simple triggers cannot access services that require authorization. So it cannot call SpreadsheetApp.openById().
https://developers.google.com/apps-script/guides/triggers#restrictions
And pay attention -- in the function sendData() you're using the name sheet but it's a spreadsheet actually. This is not an error but it can be confusing a bit.

Move row to new tab after sheet updates automatically

I need to move rows from a tab based on a cell including "lep". The problem is that it doesn't read the info already on the sheet when it's opened (since it is a sheet that automatically updates new sales from Shopify via Zapier).
What would be the solution for this? I tried onEdit & onOpen already and neither work.
function onOpen(e) {
// assumes source data in sheet named SHOPIFY
// target sheet of move to named ORG
// test column with yes is col 17 or Q
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = e.source.getActiveSheet();
var r = e.source.getActiveRange();
if(s.getName() == "SHOPIFY" && r.getColumn() == 17 && r.getValue().includes("lep")) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("ORG");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).moveTo(target);
s.deleteRow(row);
}
}
function moveRows() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('SHOPIFY');
const tsh = ss.getSheetByName('ORG')
const vs = sh.getDataRange().getValues();//you may wish to change the range to not include headers
let d=0;
vs.forEach((r,i)=>{
if(r[16].toString().includes("lep")) {
tsh.appendRow(r);
sh.deleteRow(i+1-d++);
}
});
}
function onMyOpen() {
//needs installable trigger
moveRows();
}
An onEdit() simple trigger will only run when the user hand edits the spreadsheet.
An onOpen() simple trigger will only run when you open the spreadsheet in a web browser, and its event object does not include information about any recent changes in the spreadsheet.
To detect changes made by Zapier you will need an on change installable trigger. See the moveRowsFromSpreadsheetToSpreadsheet_ script for an example of how to do that.

Sort by Named Range in Dropdown List

I am trying to create a sort function using Google Apps Script. I have about 20 columns in a Google sheet and want users to have the ability to sort the sheet by the click of a button rather than using the filter view because they keep on messing it up.
Rather than having 20 buttons for each column, I want one button with script which links to a dropdown list of Named Ranges being the same as the column headers.
Not sure if this is possible but this is a sample of my sheet:
I am struggling to get this script to work:
function sortByRangeName(rangeName){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Sheet 1');
var namedRange = ss.getRangeByName();
var startCol = namedRange.getColumn();
var lastCol = namedRange.getLastColumn();
var range = sheet.getRange('E1');
var value = range.getValue();
var rangeName = ss.getRangeByName(value);
var columnForSorting = (startCol <= dataRange.getLastColumn()) ? startCol : null;
if (namedRange && (startCol == lastCol) && columnForSorting) {
dataRange.sort({column: columnForSorting, ascending: false});
}
else {
throw new Error(Utilities.formatString("Range name: %s, startCol: %s, lastCol: %s, columnForSorting: %s", header, startCol, lastCol, columnForSorting));
}
}
This is a link to my spreadsheet:
Sample Spreadsheet
Try an Installable onEdit() with this function:
function sortByColumn(e) {
const sh=e.range.getSheet();
if(sh.getName()=='Sheet 1' && e.range.columnStart==5 && e.range.rowStart==1 && e.value) {
const hA=sh.getRange(2,1,1,sh.getLastColumn()).getValues()[0];
const col={};
hA.forEach(function(h,i){col[h]=i+1;});
const rg=sh.getRange(3,1,sh.getLastRow()-2,sh.getLastColumn());
rg.sort({column:col[e.value],ascending:true});
}
}
I believe your goal as follows.
You want to sort the range of "A3:E" with each column using the named ranges when the dropdown list at the cell "E1" on "Sheet 1" is selected.
Modification points:
In your script,
At var namedRange = ss.getRangeByName(), the argument is not used.
dataRange is not declared.
When above issues are resolved, the script works. But in this case, unfortunately, your goal cannot be achieve.
In order to achieve above goal, in this answer, the OnEdit event trigger is used.
In your dropdown list, it seems that there is the names including the space. Please be careful this. For this, I used trim().
Modified script:
Please copy and paste the following script to the script editor on the Google Spreadsheet. And, please select the dropdown list. By this, the values are sorted using the named ranges with the column selected by the dropdown list.
function onEdit(e) {
var range = e.range;
var sheet = range.getSheet();
if (sheet.getSheetName() != "Sheet 1" || range.getA1Notation() != "E1") return;
sheet.getDataRange().offset(2, 0).sort({
column: e.source.getRangeByName(e.value.trim()).getColumn(),
ascending: false
});
}
Note:
When the issues are removed from your script, it becomes as follows. I thought that knowing the modification points in your script might be help to study the script. So I also added this.
function sortByRangeName(rangeName){
rangeName = "Branch"; // This is a sample value
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Sheet 1');
var namedRange = ss.getRangeByName(rangeName.trim()); // Modified
var startCol = namedRange.getColumn();
var lastCol = namedRange.getLastColumn();
var range = sheet.getRange('E1');
var value = range.getValue();
var rangeName = ss.getRangeByName(value);
var dataRange = sheet.getDataRange().offset(2, 0); // Added
var columnForSorting = (startCol <= dataRange.getLastColumn()) ? startCol : null;
if (namedRange && (startCol == lastCol) && columnForSorting) {
dataRange.sort({column: columnForSorting, ascending: false});
} else {
throw new Error(Utilities.formatString("Range name: %s, startCol: %s, lastCol: %s, columnForSorting: %s", header, startCol, lastCol, columnForSorting));
}
}
References:
Simple Triggers
Event Objects
getRangeByName(name)
trim()

How to apply a Google Apps Script to an entire Google Sheets spreadsheet?

I'm trying to apply one script that will run on an entire Google Sheets spreadsheet, not just one tab. I have multiple tabs all with the same format; I want the script to look at the data validation in column F for every tab and if "Not Applicable" is selected for any row, move the contents of that entire row to a tab called "Not Applicable Items"
I have no experience writing scripts, so I copied the script I'm currently using from a forum topic. It successfully moves the rows to the correct tab, but only for the specified active sheet. I want the script to look at the entire spreadsheet and move any row marked "Not Applicable."
How can I do this? Here's my code:
function onEdit() {
var sheetNameToWatch = "Floorplan + Calendars";
var columnNumberToWatch = 5; // column A = 1, B = 2, etc.
var valueToWatch = "Not Applicable";
var sheetNameToMoveTheRowTo = "Not Applicable Items";
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getActiveCell();
if (
sheet.getName() == sheetNameToWatch &&
range.getColumn() == columnNumberToWatch &&
range.getValue() == valueToWatch
) {
var targetSheet = ss.getSheetByName(sheetNameToMoveTheRowTo);
var targetRange = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
sheet
.getRange(range.getRow(), 1, 1, sheet.getLastColumn())
.moveTo(targetRange);
sheet.deleteRow(range.getRow());
}
All of the scripts in a given project have access to all of the sheets in the spreadsheet. Thats why we recommend that you write you onEdit(e) script like this:
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()!="Sheet Name") return;
This limits the script from performing operations on unwanted sheets.
However, in your case you want all sheets involved in the onEdit(e) function so this is not necessary.
Personally, I wouldn't run this function in an onEdit() function because it's liable to take longer than 30 seconds. But the functionality you requested is accomplished with the following script. exclA is an array of sheet names that you don't want to include in your "Not Applicable" search like the sheet named "Not Applicable Items".
function notApplicable() {
var ss=SpreadsheetApp.getActive();
var dsh=ss.getSheetByName('Not Applicable Items')
var exclA=["Not Applicable Items"];
var shts=ss.getSheets();
for(var i=0;i<shts.length;i++) {
var name=shts[i].getName();
if (exclA.indexOf(shts[i].getName())==-1) {
var sh=shts[i];
var rg=sh.getDataRange();
var vA=rg.getValues();
var d=0;
for(var j=0;j<vA.length;j++) {
if(vA[j][5]=="Not Applicable") {
dsh.appendRow(vA[j]);
sh.deleteRow(j+1-d++)
}
}
}
}
}
I think that a lot of users over use the onEdit() capability.
You can grab each spreadsheet in a for loop by doing
for(var i = 0; i < [number of sheets]; i++){
sheet = ss.getSheets()[i];
. . . [rest of the code]
}
and include what you're trying to do inside the for loop to do with each sheet.

Google Apps Script Find bottom of column

I need some assistance with Google Apps Script. I am working in google sheets and currently have the following script:
function transpose() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('C3:N3').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Sheet21'), true);
spreadsheet.getRange("'A/P'!C3:N3").copyTo(spreadsheet.getActiveRange(),
SpreadsheetApp.CopyPasteType.PASTE_NORMAL, true);
};
Rather than just paste in A1 of Sheet 21, I would like it to find the bottom of column F. I am also wondering how to copy data from whichever sheet I am in, not just the sheet named A/P.
Thank you in advance!
You want to add the values of C3:N3 in the active sheet to the next row of last row on column F in Sheet21. If my understanding is correct, how about this modification?
Modification points :
In your script, if the active sheet is not Sheet21, the active range becomes "A1", because spreadsheet.getRange('C3:N3').activate() at other sheet is changed by spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Sheet21'), true). By this, the values of "'A/P'!C3:N3" are copied for "A1" of Sheet21.
Flow of modified script:
Retrieve the range of source (Active sheet)
Retrieve the destination (Sheet21) sheet.
Retrieve the destination range.
Copy
Modified script : Pattern 1
If the address of last row of column "F" in "Sheet21" is smaller than that of other columns, please use this.
function transpose() {
var spreadsheet = SpreadsheetApp.getActive();
var srcRange = spreadsheet.getActiveSheet().getRange('C3:N3');
var dstSheet = spreadsheet.getSheetByName('Sheet21');
var range = dstSheet.getRange('F1:F');
var values = range.getValues();
var formulas = range.getFormulas();
var i;
for (i = values.length - 1; i >= 0; i--) {
if (values[i][0] != "" || formulas[i][0] != "") break;
}
var dstRange = dstSheet.getRange("F" + (i + 2));
srcRange.copyTo(dstRange, SpreadsheetApp.CopyPasteType.PASTE_NORMAL, true);
};
Modified script : Pattern 2
If the address of last row of column "F" in "Sheet21" is larger or the same with that of other columns, please use this.
function transpose() {
var spreadsheet = SpreadsheetApp.getActive();
var srcRange = spreadsheet.getActiveSheet().getRange('C3:N3');
var dstSheet = spreadsheet.getSheetByName('Sheet21');
var dstRange = dstSheet.getRange("F" + (dstSheet.getLastRow() + 1));
srcRange.copyTo(dstRange, SpreadsheetApp.CopyPasteType.PASTE_NORMAL, true);
};
If I misunderstand your question, please tell me. I would like to modify it.