I have a Google Sheet which is storing the answers to my form and in theory should bucket the responses by the value selected from a drop down for my form labeled "Location of Change". So far the script accurately creates a new sheet from each response and adds a row with that responses information to newly created sheet, but it creates a new sheet for every response rather then add add responses that contain the same value selected from "Location of Change" to the same sheet.
I assume this is happening because there is a disconnect between the destSheet variable that looks for the values of the "Location of Change" and the getSheet() function, but I could be wrong.
Here is my code:
function onSubmit(e) {
//Open Marketing - Discoveries and Changes - v1
var sheet = e.range.getSheet();
//Return Spreadsheet that contains this sheet
var ss = sheet.getParent();
//Open Marketing - Discoveries and Changes - v1
var form = FormApp.openByUrl(ss.getFormUrl());
//Destination sheet based on "Location of Change"
var destSheet = getSheet(ss, e.namedValues["Location of Change"]);
//Store response in destination sheet
destSheet.appendRow(e.values);
function getSheet( spreadsheet, sheetName, headings) {
spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(sheetName);
if (sheet == null) {
sheet = spreadsheet.insertSheet(sheetName);
if (headings && headings.constructor === Array) {
sheet.getRange(1,1,1, headings.length).setValues([headings]);
}
}
return sheet;
}
}
I think the problem is that e.namedValues stores all values as arrays even if there is only one value. So e.namedValues["Location of Change"] should be
e.namedValues["Location of Change"][0]
Related
I have a jot form that submits data to one dedicated google sheet (DGS). I work primarily with one google sheet doc that copies cell data from the DGS. I'm trying to implement a code that when new data is entered to duplicate data and send to the google sheet doc I use regularly.
*Note. If I try to alter the DGS, it throws an error and distorts the data sent.
function copydata()
{
var sourceSheet = SpreadsheetApp.openById("Google Sheet ID").getSheetByName("Tab Sheet Name");
var targetSheet = SpreadsheetApp.openById("Google Sheet ID").getSheetByName("Tab Sheet Name");
var rangeToCopyFrom = sourceSheet.getRange(sourceSheet.getLastRow(), 2, 1, 15);
var rangeToPasteTo = targetSheet.getRange(targetSheet.getLastRow(),1,1,15);
var rangeToCopyFrom = sourceSheet.getRange("A50:N50");
var rangeToPasteTo = targetSheet.getRange("A4:N4");
rangeToCopyFrom.copyTo(rangeToPasteTo, {contentsOnly:true});
}
This could be us to append data to another spreadsheet:
function onFormSubmit(e) {
const dss = SpreadsheetApp.openById("id");
const sh = dss.getSheetByName("Destination Sheet Name");
sh.appendRow(e.values);
}
It needs to go into DGS. I'd need to know more about the date to determine if it's not duplicate data
Source:
Destination:
Hi everyone,
I have 2 google sheets, Source & Destination. I want to copy a range of data from Source sheet to Destination sheet by using google apps script. So the data should appear at the last row of the Destination sheet. This is my code:
function copyInfo() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var copySheet = ss.getSheetByName("Source");
var pasteSheet = ss.getSheetByName("Destination");
// get source range
var source = copySheet.getRange(3,1,1,10);
// get destination range
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,10);
// copy values to destination range
source.copyTo(destination);
}
Seems like the script only allow me to do the copying within one google sheet (different tab) instead of 2 different google sheet. May I know how should I modified it so that the script able to find my destination google sheet and paste the data at the last row? Any help will be greatly appreciated!
Edit
I tried to use onEdit to triggered the script, however it seems like not working. Below is my script:
function onEdit(e) {
if (e.range.columnStart == 11 && e.range.rowStart == 3){
var ss = SpreadsheetApp.getActiveSpreadsheet();
const id ='1r5Hygl5ysahMi6DQ3duDR5L8c4aGX_0CJba7lXxnejw';
var copySheet = ss.getSheetByName("Sheet1");
var pasteSheet = SpreadsheetApp.openById(id).getSheetByName("Sheet1");
if (e.value == 'Submit'){
var source = copySheet.getRange(3,1,1,10);
const values = source.getValues();
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,10);
destination.setValues(values);
}
}
}
Source:
https://docs.google.com/spreadsheets/d/1jnOvE-Dc7y9o7GsgN9fjOXZWlUCwiJayugX5q4Y3CA0/edit#gid=0
Destination:
https://docs.google.com/spreadsheets/d/1r5Hygl5ysahMi6DQ3duDR5L8c4aGX_0CJba7lXxnejw/edit#gid=0
Use Range.getValues() and Range.setValues()
const id ='ID of paste Spreadsheet';
var pasteSheet = SpreadsheetApp.openById(id).getSheetByName("Destination");
var destination = pasteSheet.getRange(pasteSheet.getLastRow()+1,1,1,10);
const values = source.getValues();
destination.setValues(values);
The method getSheetByName is used to define a sheet within a spreadsheet. To define a specific spreadsheet, you should use openById and associate the spreadhseet ID (https://docs.google.com/spreadsheets/d/{spreadsheet ID}/edit).
Define your source sheet as:
var copysheet = SpreadsheetApp.openById('enter id for Source').getSheetByName('Sheet 1')
Define your destination sheet as:
var pastesheet = SpreadsheetApp.openById('enter id for Destination').getSheetByName('Sheet 1')
If I understand correctly, your goal is the following:
/* Every time a user sets the value of cell K3 in source spreadsheet
to "submit". Copy all the values of row 3 and paste them into the
destination sheet under the last row. Then delete the source values
and set the value of K3 to "Clear" again. */
You need a installed trigger and a function to copy the values when triggered. So lets do that step by step.
Example:
First lets create a script that is bound to your source SS. Let's edit your copyInfo() function so that it takes the destination spreadsheet Id as parameter.
function copyTo(destinationSSId) {
// Open source SS at tab named "Source"
let copySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
// Open destination SS at tab named "Destination"
let pasteSheet = SpreadsheetApp.openById(destinationSSId).getSheetByName("Destination");
// Get source values
let sourceValues = copySheet.getRange(3, 1, 1, 10).getValues();
// Set values to destination range
pasteSheet.getRange(pasteSheet.getLastRow() + 1, 1, 1, 10).setValues(sourceValues);
// Log the pasted values from the last row
console.log("Last row pasted: " + pasteSheet.getRange(pasteSheet.getLastRow(), 1, 1, 10).getValues()[0]);
}
Make a function to clear the source values and reset the "form".
function clearSubmission() {
let copySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
copySheet.getRange(3, 1, 1, 10).clearContent()
copySheet.getRange(3, 11, 1, 1).setValue("Clear");
console.log("Source submitted and cleared.")
}
Set up the function to trigger.
function myTriggeredFunction(e) {
console.log(JSON.stringify(e.range), e.value)
if (e.range.columnStart == 11 && e.range.rowStart == 3) {
if (e.value == 'Submit') {
let destinationSSId = '{YOUR DESTINATION SS ID}';
copyTo(destinationSSId);
clearSubmission();
}
}
}
Install the trigger as "From spreadsheet - On edit" to run the function myTriggeredFunction by going to the "Triggers" tab in your project.
I have a spreadsheet with two different tabs in it. When I pass the link of the second tab, the below code always brings the content of the first tab in the sheet. New to appscript programming, any leads would be appreciated!
const currentSheetName = sheet.getSheetName();
if (currentSheetName == "AAA")
{
var sheetData = sheet.getRange('A1:A50').getValues();
for(var input=1;input<sheetData.length;input++)
{
var newURL = sheetData[input][0];
var cellrow = input+1;
if (newURL != "")
{
try{
var url = sheet.getRange(cellrow,1).getRichTextValue().getLinkUrl();
if (url != "")
{
var dataSheet = SpreadsheetApp.openByUrl(url);
}
else{
var dataSheet = SpreadsheetApp.openByUrl(newURL);
}
var job = dataSheet.getRange('M9').getValue();
}
}
}
openByUrl() returns a Spreadsheet, not a Sheet. You can use getSheetByName() or similar to get the actual sheet.
Structure of the Spreadsheet service
In general the structure of the data in the Apps Script Spreadsheet service is:
SpreadsheetApp > Spreadsheet > Sheet > Range > Data
Which is like:
Service > File > Sheet > Selection > Data
Hence the regular snippet you see at the beginning of many scripts:
ss = SpreadsheetApp.openById("<ID>")
sh = ss.getSheetByName("<SHEET NAME>")
rng = sh.getRange("<RANGE>")
data = rng.getValues()
Though as you have found, calling getRange on a Spreadsheet object does actually return a range. It will usually default to the first sheet in the spreadsheet. Though it is advisable to always explicitly assign the sheet, even if the spreadsheet only contains one sheet.
References
Services and methods of:
SpreadsheetApp service
spreadsheet object
sheet object
range object
Copies of a master Google Form are emailed to groups. When a member of each group completes the form, the response is sent to a sheet in a Google Spreadsheet. If there are 10 groups, there would be 10 sheets in the spreadsheet.
The name of each sheet would default to Form Responses 1, Form Responses 2, Form Responses 3... etc.
How to change the Form Response sheet name to the name of the group.
Here is what I have attempted.
var form = FormApp.openById(copyForm.getId());
var formLink = form.getPublishedUrl();
var masterSpreadsheet = SpreadsheetApp.openById("ID");
form.setDestination(FormApp.DestinationType.SPREADSHEET, masterSpreadsheet.getId());
var sheets = masterSpreadsheet.getSheets();
for(var i = 0; i < sheets.length; i++) {
if(sheets[i].getFormUrl() == formLink) {
sheets[i].setName("Group Name");
}
}
It's renaming the sheet before the newly added sheet in the spreadsheet.
Thanks in advance.
One broad way is to create a table of group names and spreadsheets URL then use it to rename the sheet.
One way to implement the above, could be to use an on form submit trigger to rename the sheet: if the sheet has the default name pattern, rename the sheet accordingly.
var table = [
['Group A', 'url1'],
['Group B', 'url2']
]
function respondToOnFormSubmit(e){
var sheet = e.range.getSheet();
var name = sheet.getName();
if(/^Form Responses/.test(name)){
var url = sheet.getFormUrl();
var newName = table.filter((row) => return row[1] === url;)
if(newName.length > 0){
sheet.setName(newName[0]);
}
}
Related
Different Google Form Urls (How to find the linked "Form Responses" sheet) in a large Spreadsheet?
Here's how I worked around the issue:
//After your current setDestination line below:
form.setDestination(FormApp.DestinationType.SPREADSHEET, masterSpreadsheet.getId());
//insert a new sheet which will be at index [0]. This forces the sheet linked to the form created first at index [1].
// rename the sheet at index [1] -- your form response sheet
// delete the newly inserted sheet at index [0]
You may need to call SpreadsheetApp.flush() to ensure the list of spreadsheets returned by getSheets is complete. There might also be a more straightforward way by testing the names of spreadsheets, or assuming index 0 is the spreadsheet you want to rename.
var form = FormApp.openById(copyForm.getId());
var formLink = form.getPublishedUrl();
var masterSpreadsheet = SpreadsheetApp.openById("ID");
form.setDestination(FormApp.DestinationType.SPREADSHEET, masterSpreadsheet.getId());
// Flush changes
SpreadsheetApp.flush();
var sheets = masterSpreadsheet.getSheets();
for(var i = 0; i < sheets.length; i++) {
if(sheets[i].getFormUrl() == formLink) {
sheets[i].setName("Group Name");
}
}
I've written an apps script in GSheet to:
Copy the last row of the Google Form sheet in Google Sheet file if a new entry arrived (trigger) by Google Form
Paste this row to another sheet in the same GSheet file to the last row
Unfortunately it copies the last row of the Form sheet more than one time to the appropriate sheet. Sometimes two times, sometimes four times. I cannot see my mistake in the code.
I couldn't find a solution so far. I included a pause before appendRow with Utilities.sleep(5000) but w/o effect.
function myFunction() {
// Source sheet: Form is the source sheet of the Google Form
var source =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form");
// Get last row in Form
var lastrow = source.getLastRow();
// Get just the date of the Form input
var formdate = source.getRange(lastrow,7,1,7).getValue();
// Change month number to string (e.g. April)
var currentD2 = Utilities.formatDate(formdate,
Session.getScriptTimeZone(), "MMMMM");
// Identify target sheet in same Google sheet file
var target =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(currentD2);
// Identify the appropriate range of the last row of the Form sheet
// (source)
var sourceData = source.getRange(lastrow, 2,1,8).getValues();
// Append the last row of the Form sheet to the last row in the target
// sheet
target.appendRow(sourceData[0])
}
I expect that the function copies just one time the last row of the Form sheet and not multiple times.
Hello I guess that you are using an onEdit trigger to start your function.
That means that when you change the "Google Form sheet" it triggers your function which changes another sheet in the same spreadsheet which starts your trigger again.
I recommend to rename your function onEdit(e)
ref(https://developers.google.com/apps-script/guides/triggers/events)
and then condition your action with: if e.range belongs to your "google form sheet" then do something otherwise not.
function onEdit(e) {
if (e.range.getSheet().getName()='your google form sheet') {
// insert here the contents of your function
}
}
you can use either this :
function appendEntry(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var ws = ss.getSheetByName("data") // this is the sheet where new entry arrive
var ws2 = ss.getSheetByName("target") // this is the sheet where the entries will go
var data = ws.getDataRange().getValues()
var data2 = ws2.getDataRange().getValues()
for(var i=0;i<data.length;i++){
var row = data[i]
for(var k=0;k<data2.length;k++){
var row2 = data[k]
if(row2[0] != row[0]){
} // This will loop through both sheet
// If entry is already mentioned in other sheet the data will not append
}
}
ws2.appendRow(data[k]) //other wise entry will append to the next sheet
}