I need a little help with a google spreadsheet script. Currently I'm using a script to copy entire row if contition is met(checkbox TRUE/FALSE). If different condition is met(different checkbox), i need to copy that entire row to "Completed" AND the tricky part for me, I need to ONLY copy cells in A,B,P columns in that specific row to sheet "Flash" to position A,B,C.. Could someone help me? Thanks!
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Orders" && r.getColumn() == 9 && r.getValue() == true) {
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);
} else if(s.getName() == "Orders" && r.getColumn() == 15 && r.getValue() == true) {
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).copyTo(target);
var targetSheet = ss.getSheetByName("Flash");
var target = targetSheet.getRange(targetSheet.getLastRow() + 1, 1);
s.getRange(row, 1, 1, numColumns).copyTo(target);
s.deleteRow(row);
}
}
Related
I have 2 onEdit scripts as detailed below that conflict. I need to somehow combine the two scrpits in to one. The fist script autosorts when column 9 in Worksheet1 is edited.
Question 1: How to make it run if i need the same function aswell but column 11 in Worksheet2?
The other script inserts a row onEdit, however it does this on all worksheets.
Question 2: How to restrict it to run when a certain cell is adited ie:Q2 on Worksheets 1 & 2?
Question 3: How to combine both scrips into 1 script?
I am a complete novice at script writing so please make you ansers as simple as possible, thanks
Scripts I have that work separately:
Script 1 AutoSort
function onEdit(event) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
if(sheet.getName()=='Worksheet1') {
var editedCell = sheet.getActiveCell();
var columnToSortBy = 9;
var tableRange = "a3:Q999";
if(editedCell.getColumn() == columnToSortBy) {
var range = sheet.getRange(tableRange);
range.sort({column: 9, ascending: false});
Browser.msgBox("sort done");
}
}
}
Script 2 InsertRow
var ss = SpreadsheetApp.getActive();
function onEdit() {
var firstRow = 3;
var sh = ss.getActiveSheet();
var lCol = sh.getLastColumn();
var range = sh.getRange(firstRow, 3, 1, lCol);
var formulas = range.getFormulas();
sh.insertRowsAfter(1, 1);
newRange = sh.getRange(firstRow, 3, 1, lCol);
newRange.setFormulas(formulas);
}
I usually make one onEdit function, which will call some other functions one after another:
function onEdit(event) {
myFunction1(event);
myFunction2();
}
function myFunction1(event) {
// do something
}
function myFunction2() {
// do something else
}
I created an invoice template in the spreadsheet and used the attached VBA code to create a report from it (essentially it stores certain cell values into another sheet as a tabular report).I would like to port this over to Google Spreadsheet and need help in converting the VBA to corresponding JavaScript. Can you help?
Thanks
Sub InvoiceReport()
Dim myFile As String, lastRow As Long
myFile = “C: \invoices\” & Sheets(“Sheet1”).Range(“B5”) & “_” & Sheets(“Sheet1”).Range(“F1”) & Format(Now(), “yyyy - mm - dd”) & “.pdf”
lastRow = Sheets(“Sheet2”).UsedRange.SpecialCells(xlCellTypeLastCell).Row + 1
‘ Transfer data to sheet2
Sheets(“Sheet2”).Cells(lastRow, 1) = Sheets(“Sheet1”).Range(“B5”)
Sheets(“Sheet2”).Cells(lastRow, 2) = Sheets(“Sheet1”).Range(“F1”)
Sheets(“Sheet2”).Cells(lastRow, 3) = Sheets(“sheet1”).Range(“I36”)
Sheets(“Sheet2”).Cells(lastRow, 4) = Now
Sheets(“Sheet2”).Hyperlinks.Add Anchor: = Sheets(“Sheet2”).Cells(lastRow, 5), Address: = myFile, TextToDisplay: = myFile‘ Create invoice in PDF format
Sheets(“sheet1”).ExportAsFixedFormat Type: = xlTypePDF, Filename: = myFile
Application.DisplayAlerts = False
‘ create invoice in XLSX format
ActiveWorkbook.SaveAs“ C: \invoices\” & Sheets(“Sheet1”).Range(“B5”) & “_” & Sheets(“Sheet1”).Range(“F1”) & “_” & Format(Now(), “yyyy - mm - dd”) & “.xlsx”, FileFormat: = 51‘ ActiveWorkbook.Close
Application.DisplayAlerts = True
End Sub
Figured this out, thankfully I've had to do this before.
This moves the data by getting the invoice information via a map that I made as an object so it's easily looped through. The tricky part was getting the PDF of the sheet.
I accomplished this by first scoping the function with Driveapp.getRootFolder() so I can get an oAuth token later. I utilized the URLFetchApp use the spreadsheets export functionality to retrieve a PDF blob. I then take this blob, name it, convert it to a file, and insert it into your drives root folder.
//Data mapping for the invoice itself
var invoiceDetailsMap = {
'Buyer Name': {
rowIndex: 4,
columnIndex: 1
},
'Invoice Number': {
rowIndex: 0,
columnIndex: 5
},
'Total Amount': {
rowIndex: 35,
columnIndex: 7
},
'Date & Time': {
rowIndex: 0,
columnIndex: 1
}
}
//Entry point for script
function EntryPoint() {
var spreadsheet = SpreadsheetApp.getActive()
var sheet = spreadsheet.getSheetByName('Sheet1');
var dataRange = sheet.getDataRange();
var valuesRange = dataRange.getValues();
var invoiceData = GetInvoiceDetails(valuesRange);
WriteInviceDetailsToSheet(invoiceData);
GetPDF(spreadsheet, invoiceData['File Name']);
}
//Writes the invoice details to the 2nd sheet
function WriteInviceDetailsToSheet(invoiceData){
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet2');
var dataRange = sheet.getDataRange();
var valuesRange = dataRange.getValues();
var columns = GetColumns(valuesRange, dataRange.getNumColumns(), 0);
var arrayToWrite = [[]];
for(var column in columns.columns){
if(typeof invoiceData[column] !== 'undefined'){
arrayToWrite[0].push(invoiceData[column]);
}
}
sheet.insertRowAfter(dataRange.getLastRow());
sheet.getRange(dataRange.getLastRow() + 1, 1, 1, arrayToWrite[0].length).setValues(arrayToWrite);
}
//Gets the invoice details absed on the mappings
function GetInvoiceDetails(valuesRange) {
var output = {};
for(var value in invoiceDetailsMap){
output[value] = valuesRange[invoiceDetailsMap[value].rowIndex][invoiceDetailsMap[value].columnIndex];
}
output['File Name'] = 'Invoice' + output['Invoice Number'] + '_' + FormatDate(output['Date & Time'], 'MM.dd.yyyy');
return output;
}
//Gets the PDF and inserts it into drive
function GetPDF(spreadsheet, fileName){
DriveApp.getRootFolder(); //Scoping
var urlParameters = 'export?exportFormat=pdf&format=pdf&size=letter&portrait=true&fitw=true&source=labnol&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=false&fzr=false&gid=0';
var baseURL = spreadsheet.getUrl();
baseURL = baseURL.replace(/edit$/,'');
var response = UrlFetchApp.fetch(baseURL + urlParameters, {
headers: {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken() }
});
var pdfBlob = response.getBlob().setName(fileName + '.pdf');
var file = DriveApp.createFile(pdfBlob);
DriveApp.addFile(file);
}
//Reformts a date
function FormatDate(date, format)
{
var temp = new Date(date);
var output = Utilities.formatDate(temp, "PST", format);
return output;
}
//Gets a columns object for the sheet for easy indexing
function GetColumns(valuesRange, columnCount, rowIndex)
{
var columns = {
columns: {},
length: 0
}
Logger.log("Populating columns...");
for(var i = 0; i < columnCount; i++)
{
if(valuesRange[0][i] !== ''){
columns.columns[valuesRange[0][i]] = {index: i ,value: valuesRange[0][i]};
columns.length++;
}
}
return columns;
}
The following will send email notification if F6 is edited on a google sheet. I need help making it send a notification if any cell in column F is edited, not just one cell. I tried ('F6,F7, etc) and I tried F:F, those don't work.
function emailNotification(e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() !== 'Sheet1' || e.range.getA1Notation() !== ('F6')) return;
return;
var recipient = "mail#google.com";
var subject = 'SUBJECT';
var body = ' BODY OF MAIL ';
MailApp.sendEmail(recipient, subject, body);
};
Please help, I don't know where I'm going wrong. Otherwise the script works like a charm for a single cell. Just not the whole column
This will run code if any cell in column F of Sheet1 is edited.
function onEdit(e)
{
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var sheetName= sheet.getSheetName();
if(sheetName=="Sheet1"){
var editRange = sheet.getActiveRange();
var editRow = editRange.getRow();
var editCol = editRange.getColumn();
var lr = sheet.getLastRow()
var range = sheet.getRange("F1:F"+lr);
var rangeRowStart = range.getRow();
var rangeRowEnd = rangeRowStart + range.getHeight()-1;
var rangeColStart = range.getColumn();
var rangeColEnd = rangeColStart + range.getWidth()-1;
if (editRow >= rangeRowStart && editRow <= rangeRowEnd
&& editCol >= rangeColStart && editCol <= rangeColEnd)
{
Logger.log("Run Code")
//YOUR CODE HERE
}}}
I am trying to make it so if any cells between I4:AI503 on the spreadsheet listed below gets edited, it will update the timestamp in column AK.
The following code is used in this spreadsheet:
function onEdit() {
var ss = SpreadsheetApp.getActiveSheet();
if (ss.getName() == "RS3 Points") {
var range = ss.getActiveCell();
var col = range.getColumn();
var row = range.getRow();
if ((col >= 9) && (col <= 35) && (row > 3)) {
var ActiveCell = ss.getRange().getRow()
var TimestampCol = ss.getLastColumn()
var formattedDate = Utilities.formatDate(new Date(), "GMT", "dd-MM-yyyy");
var GetRange = ss.getRangeByName(ActiveCell, TimestampCol)
GetRange.setValue(formattedDate)
}
}
}
Make sure column AK is formatted as Date. Then, try this code:
function onEdit(e) {
if (e.source.getActiveSheet().getName() !== "RS3 Points" ||
e.range.columnStart < 9 || e.range.columnStart > 35 ||
e.range.rowStart < 4 || e.range
.columnStart < e.range.columnEnd) return;
e.range.offset(0, 37 - e.range.columnStart).setValue(new Date());
}
These two scripts are incredibly slow. I work with a data set of about 32 columns by 1000 rows ( growing pretty rapidly ).
I've read and even used code for treating data like an array so that you can make only one call to google-services, but I'm not sure how that can help me with this case.
I need to hide certain columns depending on which person is using the google sheet
Here is the actual code:
function HideColumns(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("A1");
sheet.hideColumn(range);
range = sheet.getRange("C1:E1");
sheet.hideColumn(range);
range = sheet.getRange("G1");
sheet.hideColumn(range);
range = sheet.getRange("I1");
sheet.hideColumn(range);
range = sheet.getRange("K1");
sheet.hideColumn(range);
range = sheet.getRange("Q1:Z1");
sheet.hideColumn(range);
range = sheet.getRange("AC1:AG1");
sheet.hideColumn(range);
}
function ShowColumns(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("A1");
sheet.unhideColumn(range);
range = sheet.getRange("C1:E1");
sheet.unhideColumn(range);
range = sheet.getRange("G1");
sheet.unhideColumn(range);
range = sheet.getRange("I1");
sheet.unhideColumn(range);
range = sheet.getRange("K1");
sheet.unhideColumn(range);
range = sheet.getRange("Q1:Z1");
sheet.unhideColumn(range);
range = sheet.getRange("AC1:AG1");
sheet.unhideColumn(range);
}
unfortunately hiding columns is a "spreadsheet only" function, no way to make it faster or in batch...
maybe you could imagine a custom UI (built with UiApp or HTMLService) to show only the user relevant data ? but that might not be possible, depending on how much you need spreadsheet specific features..., not speaking of the work it might represent.
For the ShowColumns() script, are you just needing to unhide all columns in the sheet? If so, you could at least simplify that one a bit:
function ShowColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("1:1");
sheet.unhideColumn(range);
}
You can use batch request to Sheets API (enable advanced service first) to hide/unhide multiple columns in one API call:
function changeHideForColumnsOptimized(ssId, sheetId, columns, hide)
{
let requests = [];
columns.map(col => {
// get column index/indexes
let colArray = col.split(':');
let startIndex = letterToColumn(colArray[0]) - 1;
let endIndex = letterToColumn(colArray[colArray[1] ? 1 : 0]) - 1;
let hiddenByUser = hide ? true: false;
requests.push({
updateDimensionProperties: {
range: {
sheetId: sheetId,
dimension: 'COLUMNS',
startIndex: startIndex, // start index is inclusive
endIndex: endIndex + 1 // end index is exclusive
},
properties: {
hiddenByUser: hiddenByUser
},
fields: 'hiddenByUser'
}
})
});
Sheets.Spreadsheets.batchUpdate({requests: requests}, ssId);
}
// via https://stackoverflow.com/a/21231012/555121
function letterToColumn(letter)
{
var column = 0, length = letter.length;
for (var i = 0; i < length; i++)
{
column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
}
return column;
}
An then use it like this:
function HideColumns(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
let columnsToHide = ['A', 'C:E', 'G', 'I', 'K', 'Q:Z', 'AC:AG'];
changeHideForColumnsOptimized(ss.getId(), sheet.getSheetId(), columnsToHide, true);
}
function ShowColumns(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
let columnsToUnHide = ['A', 'C:E', 'G', 'I', 'K', 'Q:Z', 'AC:AG'];
changeHideForColumnsOptimized(ss.getId(), sheet.getSheetId(), columnsToUnHide, false);
}
This answer is based on these two questions:
Hide column with Sheets API call
Convert column index into corresponding column letter