Hide Last Row not hiding from form submit - google-apps-script

I am attempting to write a script that on form submit will send two sets of data to two different spreadsheets. The data is derived from one form. It is supposed to copy the most recent entry and then hide the row to prevent duplication. I am finding that on some occasions it is not hiding the last row and multiple copies are being copied. I realize my script is probably not the most efficient, for example, I could not get a range to work!
The sleep utilities were inserted as I thought there may have been a delay in the writing of the form's input to the spreadsheet and the script was running before this was complete.
The script is attached to the form which writes to a Form Responses sheet, this is then split to a company spreadsheet and a customer spreadsheet. Well that is the intention anyway!
function copyRow(){
Utilities.sleep(2000)
var ss = SpreadsheetApp.openById('1_pnsvWtqB4CUivQZE65nFR0AG9zTOgqBVSlPZW4YCUQ'); //Source Form Input
var sheet = ss.getSheetByName('Responses');
var lastrow = ss.getLastRow();
var rowIdx = sheet.getLastRow();
var rowValues = sheet.getRange(lastrow,1,1,74).getValues();
Logger.log(rowValues);
Utilities.sleep(5000)
var destValues = []; //Data to AUSJET
destValues.push(rowValues[0][0],rowValues[0][1],rowValues[0][2],rowValues[0][3],rowValues[0][4],rowValues[0][5],rowValues[0][6],rowValues[0][7]
,rowValues[0][8],rowValues[0][9],rowValues[0][10],rowValues[0][11],rowValues[0][12],rowValues[0][13],rowValues[0][14],rowValues[0][15]
,rowValues[0][16],rowValues[0][17],rowValues[0][18],rowValues[0][19],rowValues[0][20],rowValues[0][21],rowValues[0][22],rowValues[0][23]
,rowValues[0][24],rowValues[0][25],rowValues[0][26],rowValues[0][27],rowValues[0][28],rowValues[0][29],rowValues[0][30],rowValues[0][31]
,rowValues[0][32],rowValues[0][33],rowValues[0][34],rowValues[0][35],rowValues[0][36],rowValues[0][37],rowValues[0][38],rowValues[0][39]
,rowValues[0][40],rowValues[0][41],rowValues[0][42],rowValues[0][43],rowValues[0][44],rowValues[0][45],rowValues[0][46],rowValues[0][47]
,rowValues[0][48],rowValues[0][49],rowValues[0][50],rowValues[0][51],rowValues[0][52],rowValues[0][53],rowValues[0][54],rowValues[0][55]
,rowValues[0][56],rowValues[0][57],rowValues[0][58],rowValues[0][59],rowValues[0][60],rowValues[0][61],rowValues[0][62],rowValues[0][63]
,rowValues[0][64],rowValues[0][65],rowValues[0][66],rowValues[0][67],rowValues[0][68],rowValues[0][69],rowValues[0][70],rowValues[0][71]
,rowValues[0][73],rowValues[0][74]);
// copy data from col A to col BU
var dest = SpreadsheetApp.openById('1KQ43DJsJY0RpSnFHDcVfgAWLRfLKE6OD28CFkbjpJoU').getSheetByName('Form Responses');[1];
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);
var destValues = []; //DATA to CONCATENATOR
destValues.push(rowValues[0][0],rowValues[0][1],rowValues[0][2],rowValues[0][3],rowValues[0][4],rowValues[0][5],rowValues[0][6],rowValues[0][7]
,rowValues[0][8],rowValues[0][9],rowValues[0][10],rowValues[0][11],rowValues[0][12],rowValues[0][13],rowValues[0][14],rowValues[0][15]
,rowValues[0][16],rowValues[0][17],rowValues[0][18],rowValues[0][19],rowValues[0][20],rowValues[0][21],rowValues[0][22],rowValues[0][23]
,rowValues[0][24],rowValues[0][25],rowValues[0][26],rowValues[0][27],rowValues[0][28],rowValues[0][29],rowValues[0][30],rowValues[0][31]
,rowValues[0][32],rowValues[0][33],rowValues[0][34],rowValues[0][35],rowValues[0][36],rowValues[0][37],rowValues[0][38],rowValues[0][39]
,rowValues[0][40],rowValues[0][41],rowValues[0][42],rowValues[0][43],rowValues[0][44],rowValues[0][45],rowValues[0][46],rowValues[0][47]
,rowValues[0][48],rowValues[0][49],rowValues[0][50],rowValues[0][51],rowValues[0][52],rowValues[0][53],rowValues[0][54],rowValues[0][55]
,rowValues[0][56],rowValues[0][57],rowValues[0][58],rowValues[0][59]);
// copy data from col A to col BH
var dest = SpreadsheetApp.openById('1qB4OnKF3-OXFR1kR3jewHgYeslLdmIiE3maQNx0MPbk').getSheetByName('ROAMES');[1];//
dest.getRange(dest.getLastRow()+1,1,1,destValues.length).setValues([destValues]);
Utilities.sleep(2000)
sheet.hideRows(lastrow)

I am assuming, that as the data is coming from the form so the first column will be 'Timestamp'.
So, I have copied the last row from the source spreadsheet and then compared the value of column A of this last row with the value of column A of the last row of Destination sheet, if both matches then I haven't copied the data...
Only thing that may cause an issue here is if two or more responses are submitted exactly at a same time
Try the following code:
function copyRow(){
Utilities.sleep(2000);
var ss = SpreadsheetApp.openById('1_pnsvWtqB4CUivQZE65nFR0AG9zTOgqBVSlPZW4YCUQ');
var sheet = ss.getSheetByName('Responses');
var lastrow = sheet.getLastRow();
var destValues = sheet.getRange('A'+lastrow+':BU'+lastrow).getValues();
var dest = SpreadsheetApp.openById('1KQ43DJsJY0RpSnFHDcVfgAWLRfLKE6OD28CFkbjpJoU').getSheetByName('Form Responses')
if( dest.getRange(dest.getLastRow(), 1,1,1).getValue().toString() != destValues[0][0].toString() )
dest.getRange(dest.getLastRow()+1,1,1,destValues[0].length).setValues(destValues);
var destValues = sheet.getRange('A'+lastrow+':BH'+lastrow).getValues();
var dest = SpreadsheetApp.openById('1qB4OnKF3-OXFR1kR3jewHgYeslLdmIiE3maQNx0MPbk').getSheetByName('ROAMES')
if( dest.getRange(dest.getLastRow(), 1,1,1).getValue().toString() != destValues[0][0].toString() )
dest.getRange(dest.getLastRow()+1,1,1,destValues[0].length).setValues(destValues);
};

Related

Copy Paste to another sheet

I've been using Excel for the longest time but would now need to use Google sheet for the new company that I work for. Seems like it is harder than I expected.
I am creating a form to track how long an employee finishes a certain task for a client.
A simple form that I created where I hide the details on Form!F1:J1 (F1 - Time now, G1 - Name of employee, H1 - Client name, I1 - task done and J1 - Start/End the task
I just want to copy and paste the values to the next empty row on the Tracker sheet.
I tried to search previous answers but doesn't seem to work. I always get an error message:
"ReferenceError: database is not defined"
on the var copyToSheet = database.getSheetByName('Tracker!A1'); part. Here's what I got.
function Done() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var source = ss.getSheetByName('Form');
var dataToCopy = source.getRange('F1:J1');
var copyToSheet = database.getSheetByName('Tracker!A1');
var sourceValues = dataToCopy.getValues();
var lastRow = copyToSheet.getLastRow();
copyToSheet.getRange(lastRow + 1, 1, sourceValues.length, sourceValues[0].length).setValues(sourceValues);
dataToCopy.clear({
contentsOnly: true
});
}
I was able to find the correct code somewhere and just changed it a bit.
function Done() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Form");
var pasteSheet = ss.getSheetByName("Tracker");
var source = copySheet.getRange(1,6,1,5); //from which row number, from which column number, 1, how many cells to copy
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,5);
source.copyTo(destination,{contentsOnly:true});
//this is to delete what you input on the form after it copies and pastes to the tracker
var ss = SpreadsheetApp.getActive().getSheetByName("Form");
var cell = ss.getRange("C4:C7");
cell.clearContent();
};

Looping through sheets in Google Spreadsheet and using getSheetName()

I'm writing a script to loop through each sheet in one spreadsheet and copy data from specific cells into a corresponding sheet on another spreadsheet. I am getting an error on line 18 of the below code, however, stating that it can't call the getLastRow method of null. I used a couple of Logger.log lines to check my variables and see that targetSheet is coming back as null. Any advice on what I've got wrong?
//Export each sheet's daily data to another sheet *Test Version*
function exportReports() {
var sourceSS = SpreadsheetApp.getActiveSpreadsheet();
//Open Back Production Record *Test Version*
var targetSS = SpreadsheetApp.openById("1ZJKZi-UXvqyGXW9V7KVx8whxulZmx0HXt7rmgIJpUY4");
var allSourceSheets = sourceSS.getSheets();
//For-Loop to loop through hourly production sheets, running the move data for-loop on each
for(var s in allSourceSheets){
var loopSheet = allSourceSheets[s];
var loopSheetName = loopSheet.getSheetName();
var targetSheet = targetSS.getSheetByName(loopSheetName);
Logger.log(s);
Logger.log(loopSheet);
Logger.log(targetSheet);
Logger.log(loopSheetName);
var targetRow = targetSheet.getLastRow()+1;
var currentDate = Utilities.formatDate(new Date(), "GMT-5", "MM/dd/yy");
targetSheet.getRange(targetRow, 1).setValue(currentDate);
//For-Loop to move data from source to target
for(var i=6;i<=10;i++){
var sourceRange = sourceSheet.getRange(i, 2);
var targetRange = targetSheet.getRange(targetRow, i-4);
var holder = sourceRange.getValue();
targetRange.setValue(holder);
}
}
}
Per the documentation on getSheetByName, if the target sheet name does not exist, then you get null as a return value.
getSheetByName(name)
Returns a sheet with the given name.
If multiple sheets have the same name, the leftmost one is returned. Returns null if there is no sheet with the given name.
So, the desired sheet with name specified by loopSheetName does not exist in the target workbook. Perhaps someone has created a new sheet, or renamed an existing sheet in the source workbook.
You haven't asked about it, but you can improve the performance of your copy code as well, by reading the inputs as a multi-row range array, creating a row array to hold the results, and writing that once:
var sourceData = sourceSheet.getRange(6, 2, 5, 1).getValues(); // (6,2) through (10, 2)
var output = [];
// Transpose row array to column array (could use other functions, but this is easier to understand)
for(var i = 0; i < sourceData.length; ++i) { output.push(sourceData[i][0]); }
targetSheet.getRange(targetRow, 2, 1, output.length).setValues([output]); // i0 = 6 -> 6 - 4 = 2

Copy a row to new sheet based on value in a cell

I'm trying to create a Google Script that copies rows from one Google Sheet into different sheets based on the value of a cell.
The cell value are states in the United States. The master spreadsheet has data from a registration form that is being imported into it all the time. When a new registration happens (and the data is imported into the master sheet), I'd like the script to run and copy that row of data into the appropriate state sheet.
Here's where I'm at:
Get master sheet
Find the last row
Get the value of the cell in the column "state"
Copy that row into one of 50 different sheets depending on what state it is.
Run the script every time the master sheet is updated (via an API).
Any help would be appreciated. I'm definitely a newbie when it comes to scripting and this is just hurting my head.
Here's the code I have so far:
function myFunction() {
// Get Source Spreadsheet
var source = SpreadsheetApp.getActiveSpreadsheet();
// Get Source Sheet from Spreadsheet
var source_sheet = source.getActiveSheet();
// Get Active Range from Sheet
var lastRow = sheet.getLastRow();
// Get the Value of the State Cell
var cellValue = Range.getCell(lastrow,3);
// Copy Last Row to Appropriate State Sheet
if ( cellValue == 'Alaska') {
var target = SpreadsheetApp.openById("");
var target_sheet = target.getSheetByName("Sheet1");
target_sheet.appendRow(lastRow);
}
}
With this code:
// Get Active Range from Sheet
var lastRow = sheet.getLastRow();
The getLastRow() method returns an integer. Then further down in your code, you are using the lastRow variable as the data for appendrow() which won't work;
target_sheet.appendRow(lastRow);
The code should probably be something like this:
var target = SpreadsheetApp.openById("");
var target_sheet = target.getSheetByName("Sheet1");
var lastRowOfData = source_sheet
.getRange(source_sheet.getLastRow(), 1, 1, source_sheet.getLastColumn())
.getValues(); //Returns a two dimensional array
var oneD_Array = lastRowOfData.join().split(","); //Creates a one D array
target_sheet.appendRow(oneD_Array);
The appendRow() method takes a one dimensional array. The getValues() method returns a 2 Dimensional array, so it must be converted. Because you are only getting one row of data, it's easy to convert. The outer array only has one inner array. The one inner array has all the cell values of the row.
Here's the answer for what I came up with for the code:
function myFunction() {
// Get Source Spreadsheet
var source = SpreadsheetApp.getActiveSpreadsheet();
// Get Source Sheet from Spreadsheet
var source_sheet = source.getActiveSheet();
// Get Last Row
var lastRow = source_sheet.getLastRow();
// Get Last Column
var lastColumn = source_sheet.getLastColumn();
// Get Last Row of Data
var lastRowOfData = source_sheet.getRange(lastRow, 1, 1, lastColumn).getValues();
// Creates a one dimensional array
var oneD_array = lastRowOfData.join().split(",");
// Get the Value of the State Cell
var cellValue = source_sheet.getRange(2,7).getValue();
// Copy Last Row to Appropriate State Sheet
if ( cellValue == "New York" ) {
var target = SpreadsheetApp.openById("");
var target_sheet = target.getSheetByName("Sheet1");
target_sheet.appendRow(oneD_array);
}
}

Copy a row with specific cells to another spreadsheet

I have been searching for a way to copy certain cells from a row and paste them into another spreadsheet, but all I can seem to find are ways to do that just from sheet to sheet within one spreadsheet or questions that deal with code way above my head. I'm just now learning to code in Google Spreadsheets and I can't seem to get it right. Here is my code for now, I'm working on just copying one cell first and after I can do that I'll get a loop to iterate through the row and pick the cells I want to copy.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var master = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c');
var target = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c');
var master_sheet = master.getSheetByName("Steve2");
var target_sheet = target.getSheetByName("Corbin1");
var master_range = master_sheet.getRange("A1");
var target_range = target_sheet.getRange("A1");
master_range.copyTo(target_range);
Right now it is giving me an error saying that it cannot call the getRange method of null. I'm not sure if I'm using OpenById correctly or if I can even use that in this situation.
OK I've got it working now. It copies the row perfectly and it copies only the cells I want. Now I need help with the pasting part. It copies everything fine and puts it into the other sheet great, but I need it to copy into the next available row and into the first available columns. So if row 5 is the last column of data, I need it to paste into row 6 and take up the first 6 or so columns.
This is what I have so far.
function menuItem1() {
var sss = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c'); // sss = source spreadsheet Steve2
var ss = sss.getSheetByName('Sheet1'); // ss = source sheet
//Message box asking user to specify the row to be copied
var answer = Browser.inputBox('What row would you like to copy?');
var range = parseInt(answer);
var array = [1,2,3,9,12,30];
//Runs a loop to iterate through array, using array elements as column numbers
for(var i = 0; i < array.length; i++){
var SRange = ss.getRange(answer,1,1,array[i]);
//get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
//get the data values in range
var SData = SRange.getValues();
}
var tss = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c'); // tss = target spreadsheet Corbin1
var ts = tss.getSheetByName('Sheet1'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
//Confirmation message that the row was copied
Browser.msgBox('You have successfully copied Row: ' + answer);
}
You are getting this error maybe because your spreadsheet does not have a sheet called Steve2 or Cobin1. Try using the method master.getSheets()[0], this way you will get the first sheet without using their name.
You can algo use this piece of code to check the sheets names:
for(var x in master.getSheets()) {
Logger.log(master.getSheets()[x].getSheetName());
}
best,

Accessing to sheet with gid

sorry if my question is answered somewhere else, I've been looking for answers on google all afternoon but I'm still too newbie.
I'm trying to use Google spreadsheets' scripts to access to a different spreadsheet.
The only information I have is the spreadsheet's URL, where it has the key and the gid (some kind of chronological index for multi-sheet spreadsheets - only information i could find is here).
The sheet URL is something like https://docs.google.com/spreadsheet/ccc?key=abc123#gid=178
And the sheet it links to is the first sheet in the spreadsheet.
How do I find the sheet that maches the gid?
The following doesn't work, since it's based on the sheets' order, not the time they are created:
var ss = SpreadsheetApp.openById("abc123");
var sheet = ss.getSheets();
Browser.msgBox(sheets[178].getIndex());
I would do something simple like this:
var refSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SHEET NAME HERE");
var refSheetId = refSheet.getSheetId().toString();
And then append the refSheetId to the end of the getUrl string
var ssUrl = SpreadsheetApp.getActiveSpreadsheet().getUrl()+"#gid="+refSheetId;
Hope this helps!
This is how i do it:
function getSheetByGid(spreadsheet, gid){
gid = +gid || 0;
var res_ = undefined;
var sheets_ = spreadsheet.getSheets();
for(var i = sheets_.length; i--; ){
if(sheets_[i].getSheetId() === gid){
res_ = sheets_[i];
break;
}
}
return res_;
}
var sheet = SpreadsheetApp.openById("YOUR_SHEET_ID_HERE");
var seetWithGid = getSheetByGid(cpSheet, "YOUR_GID_HERE");
I know this is late, and may not be useful to original requester anymore. But I saw this question as I was working on the functionality, but ended up solving it myself later. You can look up a sheet by gid, and the fact that it doesn't change when you delete the sheet is a good thing.... if that's how you intend to use it. Basically I get all sheets, and loop through sheet names and sheet gid until the gid matches, and then I call the sheet by name.
Here's part of some code I use to take a row, from a aggregated sheet on edit, and push to the sub sheet as part of a two way sync. If you have just the gid and key stored, you can skip the steps i showed, and just reference those values. It seems to work very quick, it's a more complicated script then running from the workbook with the broken out sheets but both scripts take almost exactly 2 seconds to push, which is acceptable for me.
function Stest()
{
SpreadsheetApp.flush();
var sheet = SpreadsheetApp.getActiveSheet();
var r = sheet.getActiveRange();
var lastColumnRow = sheet.getLastColumn();
var activeRow = r.getRow();
var dataRange = sheet.getRange(activeRow,1,1,lastColumnRow);
var data = dataRange.getValues();
var sskeytemp = data[0][10].split("=")[1]; //the sheet url is in column k
var sskey = sskeytemp.split("#")[0]; //these first two steps get the sheet key
var ssid = data[0][10].split("gid=")[1]; //this last step gets the gid
var wrkbk = SpreadsheetApp.openById(sskey).getSheets(); //this gets the sheets from the workbook
for (var i = 0 ; i < wrkbk.length ; i++ ) {
if( ssid == wrkbk[i].getSheetId() ){ //this is to say if the spreadsheet gid, which is the gid of the sheet i know, matches the gid in the workbook from the link, thats the sheet i'm looking for
var ssname= wrkbk[i].getName();
var ss = SpreadsheetApp.openById(sskey).getSheetByName(ssname); //give me that sheet by name
var sslastColumn = ss.getLastColumn();
var sslastRow = ss.getLastRow();
var dataRange = ss.getRange(1,1,sslastRow,sslastColumn);
var data2 = dataRange.getValues(); //here's your data range, you can proceed freely from here
It is best not to rely on the gid for many reasons
A deleted sheet will not show up in your getSheets() method but will have accounted for in the gid
For example:
Create Sheet1 (by default, gid#1)
Create Sheet2 (gid#2)
Delete Sheet2
Create Sheet3 (gid#3)
The order will be jumbled up if the user decides to move sheets around in Spreadsheet UI. getSheets returns the sheets in the order they are arranged in the spreadsheet.
The only way you can get to the sheet is by its name. ALternatively, if you know of some content in the sheet, you can search through each sheet.
Alternatively this works for me perfect:
function _getSheetId() {
var getSpreadsheetURL = SpreadsheetApp.getActiveSpreadsheet().getUrl();
var mat = getSpreadsheetURL.match(/^(https:\/\/docs\.google\.com\/spreadsheets\/d\/)([a-zA-Z0-9]+\/)/g);
Logger.log(mat.toString()+"#gid="+SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getSheetId());
}