Writing in a newly created Google spreadsheet using an external script - google-apps-script

I have built a short script that takes inputs from a Google Form and creates a new spreadsheet. But when I try to set that values inside the sheet, nothing happens. Not sure if this is due to my code or to the lack of authorization given this is a newly created file. Here is my code:
var templates = DriveApp.getFilesByName('Template'); // get the files named Template (only one)
var template = templates.next(); // get the first files in the list
var newFile = template.makeCopy(name,newFolder); // Make a copy of the Template file and put it in NewFolder
var ss = SpreadsheetApp.open(newFile);
var sheet = ss.getSheets()[0];
sheet.getActiveRange('B1').setValue(name);
Thanks for your help

I think that in your script, an error occurs at getActiveRange('B1'). Because the method getActiveRange() of Class Sheet has not arguments. Ref I think that this is the reason of your issue. In this case, an error like The parameters (String) don't match the method signature for SpreadsheetApp.Sheet.getActiveRange. occurs. I thought that the reason of nothing happens might be that from your question, the script is run by the OnSubmit event trigger might be used. In this case, please modify as follows.
From:
sheet.getActiveRange('B1').setValue(name);
To:
sheet.getRange('B1').setValue(name);
When you modify like above and run again, the value of name is put to the cell "B2" on the 1st tab in the created Spreadsheet.
Note:
If you want to append the values when the script is run, please modify sheet.getActiveRange('B1').setValue(name); as follows.
sheet.appendRow([, name]); // In this case, the value is append to the column "B".
References:
getActiveRange()
getRange(a1Notation)

Related

Google Sheets App Script Edit Protected Cell or Object Error

I have a Google Sheets script that I've been using for the past 2+ years that grabs a chunk of data and transcribes it into a pair of tally sheets, then clears the cells that had been filled creating said chunk of data so the process can be started over. This is used for an inventory calculation system. The script has reliably worked up until roughly 3 weeks ago, but I now encounter an edit protection error when users with limited access to the sheet attempt to run the script. None of the editable cells/ranges reference in the script are locked to any user, but the sheet does have protection on cells I do not want anybody to make inadvertent changes to.
The script is:
function CopyErADD() {
var sss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = sss.getSheetByName('ADDER'); //Entry Sheet
var rangeIn = sheet.getRange('B32:N45'); //Range to copy into "Incoming" sheet
var dataIn = rangeIn.getValues();
var ts = sss.getSheetByName('Incoming'); //Tally sheet in
ts.getRange(ts.getLastRow()+1, 1, dataIn.length, dataIn[0].length).setValues(dataIn);
var rangeOut = sheet.getRange('B48:O54'); //Range to copy into "Outgoing" sheet
var dataOut = rangeOut.getValues();
var tss = sss.getSheetByName('Outgoing'); //Tally sheet out
tss.getRange(tss.getLastRow()+1, 1, dataOut.length, dataOut[0].length).setValues(dataOut);
SpreadsheetApp.flush() // NEWLY ADDED PER METAMAN'S SUGGESTION
sheet.getRange('E2:E5').clearContent();
sheet.getRange('B7:B20').clearContent();
sheet.getRange('E7:H20').clearContent();
sheet.getRange('I7:I20').setValue('kg');
sheet.getRange('L7:L20').clearContent();
sheet.getRange('B24:B29').clearContent();
sheet.getRange('J24:J29').clearContent();
}
I also have an "erase only" script that runs the second second part of the script only (if data has been entered incorrectly) that executes perfectly fine. It is only when coupled with the copy/transcribe portion of the script that the protection error occurs.
function ErADD() {
var sss=SpreadsheetApp.getActiveSpreadsheet();
var sheet = sss.getSheetByName('ADDER');
sheet.getRange('E2:E5').clearContent();
sheet.getRange('B7:B20').clearContent();
sheet.getRange('E7:H20').clearContent();
sheet.getRange('I7:I20').setValue('kg');
sheet.getRange('L7:L20').clearContent();
sheet.getRange('B24:B29').clearContent();
sheet.getRange('J24:J29').clearContent();
}
Commenting out the sheet.getRange.... etc clearContent and setValue portion of the first script allows it to complete successfully, so I attempted to create a master function that calls the CopyErAdd script (sans clear portion) and then calls the ErADD script, and I encounter the same error. Both script can be run on their own successfully, but when combined the erase portion encounters the error.
Does anybody see any issues that I am missing, or did something occur over the past few weeks that I'm not aware of that could cause this protection error?
I appreciate any ideas anybody might have.
Edit - Thank you MetaMan for the tips for making the script more efficient.
As for the protection, "Incoming" and "Outgoing" copy destination sheets are completely open, no protection at all. "ADDER" sheet is protected except certain cells that are edited by user, and are referenced in the script.
E2:E5 (actually E2:I5 open, since the macro button sits on top of the F2:I5 range), B7:B20, E7:I20, L7:L20, B24:B29, J24:J29, All unprotected.
Adding the line
SpreadsheetApp.flush()
in between the copy section and clearing section of the code worked (as shown in the updated code snippet). I'm no longer encountering a range protection error.
I really appreciate the fix, but I'm boggled over why I've never needed that line until recently. I guess you don't need flush() until you do.
You could replace this:
sheet.getRange('I7').setValue('kg');
sheet.getRange('I8').setValue('kg');
sheet.getRange('I9').setValue('kg');
sheet.getRange('I10').setValue('kg');
sheet.getRange('I11').setValue('kg');
sheet.getRange('I12').setValue('kg');
sheet.getRange('I13').setValue('kg');
sheet.getRange('I14').setValue('kg');
sheet.getRange('I15').setValue('kg');
sheet.getRange('I16').setValue('kg');
sheet.getRange('I17').setValue('kg');
sheet.getRange('I18').setValue('kg');
sheet.getRange('I19').setValue('kg');
sheet.getRange('I20').setValue('kg');
with this:
sheet.getRange('I7:I20).setValue('kg');
also replace this:
var ss = sss.getSheetByName('ADDER'); //Entry sheet
var sheet = SpreadsheetApp.getActive().getSheetByName('ADDER');
with this:
var sheet = sss.getSheetByName('ADDER);
If you are doing anything immediate after this function with the data then you might wish to add SpreadsheetApp.flush()
I can't comment on the protection since none of that information was provided.

Populate rows with the sheets names of an spreadsheet

I have an spreadsheet that contains multiple sheets with some recipes. I'm storing the sheets' titles in the first sheet manually, to reference the recipes titles on another spreadsheet, but this doesn't scale well, so I want to automate the process. I believe I can't do that with any of the built in functions, so I'm trying to build a custom function to do it.
I already know some coding, but my experience with google API is very limited. My current attempt is returning the following exception: "You do not have the permission to call set value". After google this error, I discovered that custom functions seemingly cannot set values to another cells, so I'm here to find an alternative to such a trivial behavior.
This is my current code:
function updateSheetTitles() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var cell = SpreadsheetApp.getActiveSpreadsheet().getCurrentCell();
var row = cell.getRow();
var column = cell.getColumn();
for (var i=0 ; i<sheets.length ; i++){
if(i<1) //For passing trought the first sheet
return;
cell.setValue(sheets[i].getSheetName);
var range = SpreadsheetApp.getActiveSheet().getRange(row+1, column, 1, 1);
cell = SpreadsheetApp.getActiveSheet().setCurrentCell(range);
}
}
And here's and image to illustrate what I want:
This is probably an easy task, but I failed to find a way to build this, so any ideas to accomplish that would be appreciated.
I believe your goal as follows.
You want to retrieve sheet names in the active Google Spreadsheet.
You want to put the sheet names to the active cell.
You want to achieve this using the custom function.
Modification points:
Unfortunately, setValue cannot be used in the custom function. I think that the reason of your issue is due to this.
In your script, at cell.setValue(sheets[i].getSheetName);, the method of getSheetName is not run. If you want to use this method, please add () like getSheetName().
SpreadsheetApp.getActiveSpreadsheet() can be declared one time.
In order to achieve your goal, I would like to propose a custom function for creating an array including the sheet names and returning the array.
When above points are reflected to the sample script, it becomes as follows.
Modified script:
Please copy and paste the following script to the script editor of Google Spreadsheet. And, please put the custom function of =updateSheetTitles() to a cell. By this, the sheet names are returned to the row direction.
function updateSheetTitles() {
return SpreadsheetApp.getActiveSpreadsheet().getSheets().map(e => [e.getSheetName()]);
}
From your replying, when you want to retrieve the sheet names except for 1st and 2nd sheet, you can also use the following script.
function updateSheetTitles() {
return SpreadsheetApp.getActiveSpreadsheet().getSheets().map(e => [e.getSheetName()]).slice(2);
}
References:
Custom Functions in Google Sheets
map()
getSheetName()

sheet.getLastRow() not working when launched by trigger

A short description of the issue:
When running an automatic script with trigger head timebased the script failed
With the following error description
Exception: The starting row of the range is too small. at fetchData(wkapi2:4:20)
(which means that the sheet is empty) and this is not the case the sheet has 300 rows.
It worked well until 2 days ago....I did not change the script nor any settings
When I run the script manually, then everything works fine...
The line of code is as follows :
function fetchData() {
var options = {'Cache-Control' : 'max-age=0, must-revalidate'}; //I've used this before to try and prevent google from giving me cached data when making API calls..seems to get the job done
var sheet = SpreadsheetApp.getActiveSheet(); //This script is bound to the corresponding sheet so we can use this conveinience method
var cell = sheet.getRange(sheet.getLastRow(),1); //Get a reference to current last cell in Column A
The scripts Fails at the
sheet.getRange (... ) function when automatically run
When I run manually it works
When run without a "active" spreadsheet, (i.e., a spreadsheet that is visible in the browser), "active" sheet would refer to the first sheet. Use Spreadsheet.getSheetByName() instead of getActiveSheet().

Need Script for Google Docs to Send Auto Email

I'm looking for a script that I can add to a Google sheet that will auto generate an email and include some of the fields in the spread sheet.
I had created a Google Form and I have that data going to the Google spreadsheet, the idea is when the user submits the form it sends that data to the spreadsheet and the spreadsheet sends an automated email.
I found this script and edited it some but it fails on the 4th line (var theEvent = e.values[1]):
function AutoConfirmation(e){
var theirFirst = "Bill";
var theirEmail = johndoe#example.com;
var theEvent = e.values[1];
var subject = "Form Submitted";
var message = "Thank you, " + theirFirst + " for the expressed interest in our " + theEvent;
MailApp.sendEmail (theirEmail, subject, message);
}
Shouldn't line 4 pull the data from column 1 in my google sheet? Is this old an script and it doesn't work now?
In my google sheet I have Site instead of event as a column and another that has Complete as a header.
Let me know what I have missed here as it seems that this should be simple.
I tried to run this and this is the result: screenshot of the error I get
I get the same type of error when running the code above so I thought I would run a logger to see if I get anything with that and the result is in the screen shot. Click the link to see it.
It looks that the script that you found is function to be put in a Apps Script project bounded to a Google spreadsheet and called by an installable trigger.
Shouldn't line 4 pull the data from column 1 in my google sheet?
No. e.values returns an Array which use a zero based index. This means that index for Column A, the first column, is 0.
Issue:
The error you are getting:
TypeError: Cannot read property 'values' of undefined
Means that the event object (e) is undefined, which means that you are trying to run this function manually. Functions that are attached to a trigger are supposed run when the corresponding trigger event happens: in this case, when a user submits the Form. You don't have to run it manually.
Solution:
Step 1: Install the trigger: If you haven't done so yet, install the trigger, either manually, following these steps, or programmatically, by copy the following function to your bound script and running it once:
function createOnFormSubmitTrigger() {
var ss = SpreadsheetApp.getActive();
ScriptApp.newTrigger("AutoConfirmation")
.forSpreadsheet(ss)
.onFormSubmit()
.create();
}
Step 2: Submit the form!: Once the trigger is installed, when a user submits the Form that is attached to your Spreadsheet (that is, assuming that you have attached the Form to the Spreadsheet), AutoConfirmation runs automatically, and the event object, containing these properties, is passed as an argument. If you run it manually, e is undefined (no event object is passed as parameter), and you get the error.
Note:
e.values[1] will retrieve the same value that is written to column B when the form is submitted, since JavaScript arrays are zero-indexed. You might want to use e.namedValues['yourProperty'] instead, to make sure your are retrieving the desired information.
Reference:
SpreadsheetTriggerBuilder.onFormSubmit()
Event Objects: Form submit

Create a new sheet in an existing spreadsheet for EACH RESPONSE from a Google Form

I have created a Google form, and I need to create a new sheet in an existing spreadsheet for each response I receive from this form - each respondent generates a new sheet within the spreadsheet. Is this possible with some kind of onSubmit command? I'm completely new to Javascript but willing to learn. Thanks so much for your help.
You can't intercept a Google Form submission before the data is written into the spreadsheet. All you can do is manipulate the data after it's already been inserted into the spreadsheet. So, your responses will get put into the spreadsheet, all in one sheet to start with. You can't change that.
Now the question is, do you want to manipulate the data from code bound to the form or bound to the sheet? You'll want to use a project bound to the sheet.
This is some sample code:
This code assumes that the value you want to name your sheet is in column A
function subTheForm() {
Logger.log('submit ran');
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
//Get last row of data
var lastRow = sheet.getLastRow();
var colA_Data = sheet.getRange(lastRow, 1).getValue();
//var thisUser = 'theUserName';
ss.insertSheet(colA_Data);
};
Old answer:
You'll need to generate some kind of unique string every time a new form is submitted. I have no idea what you want. You could get the user name, then add the date/time to it, then name each new sheet the user name with the time. The basic code will look like this:
function submit(){
Logger.log('submit ran');
var thisUser = 'theUserName';
var ss = SpreadsheetApp.getActive().insertSheet(thisUser);
};
Note the Logger.log(); statement. That prints something to the LOG. Inside the code editor, you can select the VIEW menu, and the LOGS menu item to show the LOG.
You can also run the code "manually" from the code editor by selecting the function name and clicking the run arrow icon. That way you can run the code without submitting a form every time. Get the code to work, then wire it up to the onsubmit trigger.
For this you can get the Spreadsheet using this command(getActiveSpreadsheet()) and then create a new sheet based on the parameters you require from this page. you can add this lines of code in your onSubmit trigger.
Hope that helps!