Is it possible to get the destination sheet from app script - google-apps-script

I am trying to identify the destination sheet for a google form. I can get the spreadsheet using:
function getDataSheet(){
var form = FormApp.getActiveForm();
var id = form.getDestinationId();
var ss = SpreadsheetApp.openById(id);
var sheet = ""; // how do I get the sheet that the data will go to?
}
The problem is how can I get the sheet that the form results will go to? I can guess that it is [0], but that is not a guarantee.

var form = FormApp.getActiveForm();
var formId = form.getId();
var sheets = ss.getSheets();
for(i=0; i<sheets.length; i++){
var sheetFormURL = sheets[i].getFormUrl();
if(sheetFormURL) {
if(sheetFormURL.indexOf(formId)!=-1) {
var sheet = sheets[i];
break;
}
}
}
if(typeof sheet !== 'undefined'){
//do what you need to do in the sheet
}

Currently, there is no "built-in" way to get the sheet tab of the Form destination.
If the user of the spreadsheet has not changed the default sheet name given, then you can loop through all the sheets, get the sheet name, and check for a name that includes the text: "Form Responses".
The first default name given is:
Form Responses 1
Then, if more destinations are added, the number at the end is increased.
If the user changes the name, then obviously, you can not use that strategy. If you can get the sheet tab name as soon as the new destination is created, then store the sheet tab ID in the documents properties, that would ensure that you have the information available. Having the sheet tab ID is better than having the sheet tab destination name, that way, if the destination sheet tab name gets changed, you can still find the correct sheet tab by looking the ID up from the document properties, then using the ID to get the sheet tab.
If the spreadsheet has multiple Form Responses X sheets, and you wanted to get the last destination added, you would need to get the number off the end, and find out what the highest number is.
There should be a way to get the destination sheet tab. I don't know if there is a feature request for that or not.

This is what I am doing as a workaround. It will try and find the datasheet, and should work for most forms. It is not very efficient, but should hopefully work to get most forms.
function getDestinationSheet(ss){
if(!ss){
var form = FormApp.getActiveForm();
var id = form.getDestinationId();
ss = SpreadsheetApp.openById(id);
}
var possibleDS = [];
var allSheetNames =[];
var dsName = {};
var locale = ss.getSpreadsheetLocale();
var text = "Timestamp";
if(locale != "en_US"){
text = LanguageApp.translate(text, "en_US", locale);
}
var sheets = ss.getSheets();
for(i in sheets){
var s = sheets[i];
var sName = s.getName();
allSheetNames.push(sName);
var a1 = s.getRange("A1").getValue();
if (a1 == text){ possibleDS.push(sName) }
}
var l = possibleDS.length;
switch (l){
case 0:
dsName.name = "Error";
dsName.error = "No matches found";
dsName.sheets = allSheetNames;
break;
case 1:
dsName.name = possibleDS[0];
dsName.error = "Sucess";
break;
default:
dsName.name = "Error";
dsName.error = "Unable to determine destination sheet using timestamp";
dsName.sheets = possibleDS;
break;
}
return dsName;
}

Related

getValues and getBackgrouds not returning data in Google Apps Script

I'm trying to create a code that checks to see if a cell has a checkbox checked (or unchecked) and then copies data from a corresponding cell on that row onto another "Summary" sheet. The "if checked then copy data" portion has not been included below.
The problem I'm having is that neither getValues nor getBackgound seems to be returning data.
When I run my code, the Logger shows that every checkbox value is "false" (even though some are checked and I have their values set to 1 (checked) and 0 (unchecked) using the data validation in the spreadsheet settings.
If I switch to getBackgrounds, the Logger shows that every cell's background is white "#ffffff", even though the cells are red.
[[I want my code to iterate over every sheet, row, and column. It seems to be iterating fine, but not retrieving the data.]]
What I am doing wrong? Here's my full code:
function MAPSuccess() {
var app = SpreadsheetApp;
var ss = SpreadsheetApp.openByUrl(
'https://docs.google.com/spreadsheets/d/1UUdiLsz2OvKdqnr2KB0Tx74gzrGx0m4XUA5oNMUB06k/edit');
var allsheets = ss.getSheets();
var s = ss.getNumSheets();
var master = app.getActiveSpreadsheet().getSheetByName("Master");
var masterLastRow = master.getLastRow();
for (var s = 2; s < allsheets.length; s++) {
var sheet = app.getActiveSpreadsheet().getActiveSheet();
var r = sheet.getCurrentCell().getRow();
var lastrow = sheet.getLastRow();
var lastcol = sheet.getLastColumn();
var temail = sheet.getRange(1,2);
var tSJCOE = sheet.getRange(2,2);
var c = sheet.getActiveCell().getColumn();
for(var r = 4;r<=lastrow;r++){
var name= sheet.getRange(r,1).getValue();
var lname= sheet.getRange(r,2).getValue();
var email= sheet.getRange(r,3).getValue();
var pemail= sheet.getRange(r,4).getValue();
var info = [
[name, lname, email, pemail]
]
var range = sheet.getRange(r,1,1,lastcol);
var rowValues = range.getValues();
var cell = [
[s,r,c]
];
Logger.log(rowValues);
Logger.log(name);
// Logger.log(checkRow);
Logger.log(cell);
It looks like you are always performing your actions on the active sheet, instead of accessing the sheets in "allsheets".
var sheet = app.getActiveSpreadsheet().getActiveSheet();
should be
var sheet = allsheets[s];
You may also be misusing "getCurrentCell" on the next line, since that will return whichever cell is currently selected in the spreadsheet, of which there is always only one, regardless of which sheet you are accessing.

Create New Sheet with Name Based on Form Submission

In Google Sheets I have a script I'm using to create a new sheet for each Google Form that is submitted. It is supposed to create a new sheet with name based on the last column, column G(which isn't a form submitted column). Then it takes the information from the last row and the heading row and copy it to the first two rows of the created sheet. It also adds formulae to cells to put the info into columns(transpose) and format it based on a created sheet.
Right now it is creating the sheet and copying the formulae and format, but not giving it the proper name or pulling the last row information.
Please help!
~Charles
I have copied the code below:
function onFormSubmit() {
// onFormSubmit
// get submitted data
var ss = SpreadsheetApp.openById(
'...');
var sheet = ss.getSheetByName("Responses");
var headings = sheet.getRange(1,1,1,
sheet.getLastColumn()).getValues();
var lastRow = sheet.getRange(sheet.getLastRow(),1,1,
sheet.getLastColumn()).getValues();
var studentUsername = lastRow[0][6];
// check if username has sheet
if(ss.getSheetByName(studentUsername)){
var userSheet = ss.getSheetByName(studentUsername);
// if not make
} else {
var userSheet = ss.insertSheet(studentUsername);
userSheet.getRange(1,1,1,
headings[0].length).setValues(headings);
}
// copy submitted data to user's sheet
userSheet.appendRow([lastRow]);
userSheet.appendRow(['=CONCATENATE(B6," ",B5)']);
userSheet.appendRow(['=TRANSPOSE(B1:2)']);
userSheet.hideRows(1,2);
userSheet.setColumnWidth(1, 500);
userSheet.setColumnWidth(2, 500);
var FormatSheet = ss.getSheetByName("Format");
var FormatRange = FormatSheet.getRange("a3:b28");
FormatRange.copyFormatToRange(userSheet,1,3,3,28);
}
With some help from the comments and playing around, i figured out the code I need. Big thanks to #Cooper!
Here it is:
function onFormSubmit() {
// onFormSubmit
// get submitted data
var ss = SpreadsheetApp.openById(
'Sheet_ID');
var sheet = ss.getSheetByName("Responses");
var row = sheet.getLastRow();
var Col = sheet.getLastColumn();
var headings = sheet.getRange(1,1,1,
Col).getValues();
var lastRow = sheet.getRange(row, 1, 1, Col);
var studentUsername = sheet.getRange(row, Col).getValue();
// check if username has sheet
if(ss.getSheetByName(studentUsername)){
var userSheet = ss.getSheetByName(studentUsername);
// if not make
} else {
var userSheet = ss.insertSheet(studentUsername);
userSheet.getRange(1,1,1,
headings[0].length).setValues(headings);
}
// copy submitted data to user's sheet
userSheet.appendRow(lastRow.getValues()[0]);
userSheet.appendRow(['=CONCATENATE(B6," ",B5)']);
userSheet.appendRow(['=TRANSPOSE(B1:2)']);
userSheet.hideRows(1,2);
userSheet.setColumnWidth(1, 500);
userSheet.setColumnWidth(2, 500);
var FormatSheet = ss.getSheetByName("Format");
var FormatRange = FormatSheet.getRange("a3:b28");
FormatRange.copyFormatToRange(userSheet,1,3,3,28);
}

GAS - Select (Get) Spreadsheet per GForm input

My 1st question in Stack Overflow.
I have a Google Spreadsheet with 4 individual sheets.
Sheet1 is responses from GForm. Sheet2,3,4 have same data but in 3 languages English, Tamil, Hindi and named English, Tamil, Hindi.
At present the Script takes cell value date from Sheet1, matches the data in the language Tamil sheet, mail merges with the correct language Tamil GDoc and emails it.
Now, I cannot figure out how to make the Script pick a different language Gsheet, one of the 3, depending upon the evalues4 from Form input, which is a Radio Button.
Can someone help me to figure it out?
Select appropriate language
Gsheet using ss.getSheetByName and
GDoc using DriveApp.getFileById
based on Form response evalues4.
Here is the code and which works fine, if I input just one language by name/sheetID/DocID.
//Get information from the form and set as variables
function onFormSubmit(e)
{
var Time = e.values[0];
var email = e.values[1];
var fog = e.values[2];
var mog = e.values[3];
var lang = e.values[4];
var do_date = e.values[5];
//Match chosen date from data sheet & get Row Number
function findInColumn() {
var data = do_date;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Tamil");
var range = sheet1.getRange(1,1,sheet1.getLastRow(),1);
var values= range.getValues();
var row = 0;
while ( values[row] && values[row][0] !== data ) {
row++;
}
if (values[row][0] === data)
return row+1;
else
return -1;
}
//Use above Row number to load in Range, get values, assign to variable cells
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet3 = ss.getSheetByName("Tamil");
// Get range of cells in All columns and All rows with entries
var dataRange = sheet3.getRange(findInColumn(), 1, 1, sheet3.getLastColumn());
// Get entries for each row in the Range.
var data = dataRange.getValues();
// Set each value to a unique variable
for (i in data) {
var cell = data[i];
// Get document template, copy it as a new doc with Name and email, and save the id
var copyId = DriveApp.getFileById("1Nxxxxxxxxxxxxxx2k")
Sorry, completely forgot that I had asked the question here. I solved it the same weekend, by using the If - else [Note: Instead of var ss I used var ssn, and instead of var sheet3 I used var tocopyID in the rewrite]
//Use above Row number to load in Range, get values, assign to variable cells
var ss = SpreadsheetApp.getActiveSpreadsheet();
if (lang === "Tamil"){
var ssn = ss.getSheetByName("Tamil");
var tocopyId = DriveApp.getFileById("1NxxxxTamil");
}
else if (lang === "Hindi"){
var ssn = ss.getSheetByName("Hindi");
var tocopyId = DriveApp.getFileById("Hindi");
}
else if (lang === "English"){
var ssn = ss.getSheetByName("English");
var tocopyId = DriveApp.getFileById("1NxxxxEnglish");
}
You could use you lang variable to get the correct sheet, since they've got the same name. Like :
var sheet1 = ss.getSheetByName(lang); // where lang = "Tamil" for example
For using the correct template, you can store the id of your template with the Properties like:
var templateId = PropertiesService.getScriptProperties().getProperty(lang); // where lang = "Tamil" for example
var copyId = DriveApp.getFileById(templateId);
Where you have properties set with the language name you want. You can set them with code :
PropertiesService.getScriptProperties().setProperty('Tamil', '1Nxxxxxxxxxxxxxx2k');

Cell reference out of range, google sheets

I'm getting this error while running this sheet.
Cell reference out of range (line 81, file "genreportSE")
I don't know why it says it's 'out of range'.
I tried to used 'copyvalues'. I saw a script where you can't really "print" a range, but you can create another spreadsheet, copy that range, then print that sheet and delete it.
How should I accomplish this?
function genreportSE() { // This function let us read the value of a cell from a sheet and change the value of another cell in a different sheet
var ss = SpreadsheetApp.getActive(); //ss stands for spreadsheet, this is the active spreadsheet
var clientsheet = ss.getSheetByName('Clientes SE');
var gensheet = ss.getSheetByName('Generador SE');
var clienttable = clientsheet.getDataRange();
var numberofservices = clienttable.getNumRows(); //The number of services in the Clientes sheet
var error1;
var error2;
var rangetocheck1;
var rangetocheck2;
var client;
var clientname;
var i=0;
var reportswitherrors = []; //Array for faulty reports
var email ='jvaldez#galt.mx';
var subject = "Reporte de producción y consumo - " + (new Date()).toString();
var body = "TEXT" ;
for (i=0;i<=2;i++){
gensheet.getRange('B2').setValue(clientsheet.getRange(i+2,1).getValue()); //This will change the cell "B2" in "Generador SE" to the current service number for the report generation
Utilities.sleep(3000); //A timer to let the importdata function get the data from the SE server in miliseconds
client = gensheet.getRange('B4').getValue;
clientname = String(client);
rangetocheck1 = gensheet.getRange('B8:C14').getValues(); //Data range that could present calculation errors ********
rangetocheck2 = gensheet.getRange('H8:H14').getValues(); //Data range that could present calculation errors ********
if(String(rangetocheck1).indexOf('#N/A') == -1) { //This checks if there are any errors in rangetocheck1
error1 = false;
} else {
error1 = true;
};
if(String(rangetocheck2).indexOf('#N/A') == -1) { //This checks if there are any errors in rangetocheck2
error2 = false;
} else{
error2 = true;
};
if(error1||error2){
reportswitherrors.push(clientsheet.getRange(i+2,1).getValue()); //This appends the current service number to the faulty services array
} else {
// Convert individual worksheets to PDF
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export",15,60);
newSpreadsheet.getSheetByName('Sheet1').activate();
var newsheet = newSpreadsheet.getSheetByName('Sheet1');
var genRange = gensheet.getRange('A1:H50').copyValuesToRange(newsheet,0,10,0,55)
var pdf = DriveApp.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Weekly Status.pdf',content:pdf, mimeType:'application/pdf'};
MailApp.sendEmail(email, subject, body, {attachments:[attach]});
DriveApp.getFileById(newSpreadsheet.getId()).setTrashed(true);
}
};
Logger.log(reportswitherrors);
}
It appears that you've got your row & column dimensions flipped between function calls. (Because Google decided to be inconsistent with the order of them...)
This line calls create(name, rows, columns):
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export",15,60);
You've created a spreadsheet with 15 rows and 60 columns.
A bit further along, probably on line 81, copyValuesToRange(sheet, column, columnEnd, row, rowEnd) gets invoked:
var genRange = gensheet.getRange('A1:H50').copyValuesToRange(newsheet,0,10,0,55)

How to get a form linked to a sheet using google app script?

In class Spreadsheet there is getFormUrl() which returns the url for the form attached to the spreadsheet, null if there is no form.
But now that you can have a form attached to each sheet, how do you get the ID or Url of the form attached to a given sheet?
You can call getFormUrl on the Spreadsheet, and on each Sheet of the Spreadsheet:
let ss = SpreadsheetApp.getActiveSpreadsheet();
let sheets = ss.getSheets();
for (let sheet of sheets) {
let sheetName = sheet.getName();
let formUrl = sheet.getFormUrl();
Logger.log("formUrl1 %s %s", sheetName, formUrl);
if (formUrl) {
Logger.log("formid1 %s", FormApp.openByUrl(formUrl).getId());
}
}
let formUrl = ss.getFormUrl();
Logger.log("formUrl2 %s", formUrl);
if (formUrl) {
Logger.log("formid2 %s", FormApp.openByUrl(formUrl).getId());
}
In my case, the spreadsheet was created by a form (in the Answers section, the green spreadsheet icon), and formUrl2 refers to this form. The formUrl1 of one of the sheets relates also to this form, because this sheet contains the answers of the form. Another sheet has the url of a second Form, because I connected the second form to the same spreadsheet. A third sheet has null as formUrl, because it is not related to a form.
I give an example for you of my script.
Maybe it can help you.
example :
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName("Sheet1");
var data = ss.getDataRange().getValues(); // Data for pre-fill
var formUrl = ss.getFormUrl(); // Use form attached to sheet
var form = FormApp.openByUrl(formUrl);
var items = form.getItems();
I just took the URL provided by the getFormUrl and assigned letters 49 through 93 to a string. That should provide the Form ID.
var ss=SpreadsheetApp.getActiveSpreadsheet();
var fOrmUrl=ss.getFormUrl();
var sTring="";
for (var i=49; i<93; i++)
{
sTring=sTring + fOrmUrl[i];
}
I've noticed that the sheet.getFormURL() method does not always return the same URL that form.getPublishedUrl() returns. Both URLs are valid, though. To get around the problem, I'm opening the sheet's formUrl and then checking and comparing that form's ID:
var form = FormApp.getActiveForm();
var formId = form.getId();
const matches = spreadSheet.getSheets().filter(function (sheet) {
var sheetFormUrl = sheet.getFormUrl();
if (sheetFormUrl){
return FormApp.openByUrl(sheetFormUrl).getId() === formId;
}
});
const sheet = matches[0]