I have 10 different google sheets. I have a very basic google apps script to apply to all of these. This is the script:
function myRecalculate() {
var ss = SpreadsheetApp.openById('sheet ID');
var sheet = ss.getSheetByName("Sheet7");
var cell = sheet.getRange('A1')
var number = Math.floor(Math.random() * 8) + 1;
cell.setValue(number)
}
And I want this to be used in 9 other sheets as well. Is there a way in GAS to avoid repeating this code 10 times? I could just copy paste and alter the sheet ID every time, but does not feel right.
Is there a simple solution?
edit. Solved it myself with packing all sheetID's in an array, and loop the function through the array:
function myRecalculate() {
var idBE = "id of spreadsheet1"
var idDE = "id of spreadsheet2"
var idFR = "id of spreadsheet3"
// pack them in array
var id = [idBE, idDE, idFR]
// loop through array, do something with sheet
for (i in id){
var ss = SpreadsheetApp.openById(id[i])
var sheet = ss.getSheetByName("Sheet7");
var cell = sheet.getRange('A1')
var number = Math.floor(Math.random() * 8) + 1;
cell.setValue(number)
}}
You can use libraries!
Here is the reference for Apps Script libraries: Libraries
Note: Code ran through libraries is not as fast as code ran directly from your project.
In short, you can create a version of your code by going to File -> Manage Versions. Save a new version. Then go to File -> Project Properties and copy the Project Key.
Go to your next Apps Script project, and go to Resources -> Libraries. Paste your project key into the Find a Library text field and click Select. Select the version of you're library that you want to use and hit save.
You can now reference the code in that Apps Script project like: MyProject.myRecalculate()
Related
Skip this paragraph, if you do not care about the background and immediately want to see the coding question.
I am pretty new to coding and this is my first question I post here, but I hope I can make some sense. I searched the web thoroughly, but I cannot find an answer to my probably not so special problem.
Some background: I work as a coach and have google spreadsheets with training plans that I give to clients. Since I love coding and google spreadsheets, the statistics and functionality I programmed quickly developed, so much, I had to split the spreadsheet and its up to 7 training day tabs/sheets in different spreadsheets, so I save my clients or rather their smartphones some working memory. So far so good.
I programmed an apps script that duplicates the master/setup sheet as well as the training days spreadsheets (#1 to #7) and customizes the folder they are saved in as well as the copies names with the clients nickname/first name.
Today I also managed to successfully replace the importranges in the calender sheet (background: so I can see when my clients trained which day) of my master/setup spreadsheet, so that the copy of the master spreadsheet, which I just duplicated, does not link to the training day #1, #2, ... template, but the copy of the training day #1,#2 ... template. I do not know how comprehensible this is (also english is not my first language) so I try to rephrase it: Of course the IMPORTRANGE formulas that interconnect all the template spreadsheets with each other do not update when duplicating, but still refer to the template spreadsheets.
However, I asked myself why hardcode everything (the actual cell ranges and stuff) and if there is not an easy possibility to always substitute the id part of all importrange functions (of template #1 for example) with the id of the sheet (which I already stored in an array).
Do you understand what I mean and could you help me with this?
Here is what I already coded so far.
Thanks to anyone who read this question and trys to help!
PS: Also I am happy if someone wants to correct or simplify my current code, but I am happy that it works so far and I would be overwhelmed if someone could push me in the right direction of how to achieve this.
PPS: The reason why I am leaning in the direction of a GAS version of find and replace all importrange functions would be, that I would keep some flexibility in my spreadsheet template architecture and I would be able to edit the template in the future without thinking about hardcoded ranges in the GAS code, that I might destroy.
Tl;Dr: Is there an easy way to use find and replace via GAS to just change the id part of the importrange formulas after duplicating spreadsheets?
//function that creates a new menu in the spreadsheet just right of the "help" tab
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Scripts')
.addItem('Create Duplicates', 'createDuplicates')
.addItem('Create Links in Master Spreadsheet', 'createLinksInMasterSheet')
.addToUi();
}
const parentFolder = DriveApp.getFolderById("ID OF PARENT FOLDER");
const nameOfMasterSheet = "TrnngPln";
const currentVersion = "4.0";
//function that creates duplicates of master sheet, all training days in a new folder that is named after the clients nickname
function createDuplicates() {
const clientNickname = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SETUP").getRange('AB2').getValue();
const currentmonth = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("InfoForAppsScript").getRange('F2').getValue();
const currentyear = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("InfoForAppsScript").getRange('G2').getValue();
const folderNewClient = parentFolder.createFolder('TP.'+clientNickname+'.['+currentmonth+'/'+currentyear+']');
const newMasterSpreadSheetName = ''+clientNickname+'.'+nameOfMasterSheet+'['+currentmonth+'/'+currentyear+'.]'+currentVersion+'';
const setup = DriveApp.getFileById("ID OF SETUP TEMPLATE");
var newMasterID = setup.makeCopy(newMasterSpreadSheetName,folderNewClient).getId();
const nameOfCopyOfDay1 = '#1.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day1 = DriveApp.getFileById("ID OF TEMPLATE DAY 1");
var newDay1id = day1.makeCopy(nameOfCopyOfDay1,folderNewClient).getId();
const nameOfCopyOfDay2 = '#2.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day2 = DriveApp.getFileById("ID OF TEMPLATE DAY 2");
var newDay2id = day2.makeCopy(nameOfCopyOfDay2,folderNewClient).getId();
const nameOfCopyOfDay3 = '#3.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day3 = DriveApp.getFileById("ID OF TEMPLATE DAY 3");
var newDay3id = day3.makeCopy(nameOfCopyOfDay3,folderNewClient).getId();
const nameOfCopyOfDay4 = '#4.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day4 = DriveApp.getFileById("ID OF TEMPLATE DAY 4");
var newDay4id = day4.makeCopy(nameOfCopyOfDay4,folderNewClient).getId();
const nameOfCopyOfDay5 = '#5.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day5 = DriveApp.getFileById("ID OF TEMPLATE DAY 5");
var newDay5id = day5.makeCopy(nameOfCopyOfDay5,folderNewClient).getId();
const nameOfCopyOfDay6 = '#6.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day6 = DriveApp.getFileById("ID OF TEMPLATE DAY 6");
var newDay6id = day6.makeCopy(nameOfCopyOfDay6,folderNewClient).getId();
const nameOfCopyOfDay7 = '#7.'+clientNickname+'['+currentmonth+'/'+currentyear+']'+currentVersion+'';
const day7 = DriveApp.getFileById("ID OF TEMPLATE DAY 7");
var newDay7id = day7.makeCopy(nameOfCopyOfDay7,folderNewClient).getId();
}
//function that sets Links in Calendar tab of master trainingplan spreadsheet
function createLinksInMasterSheet() {
var searchFor = ['title contains ".TrnngPln"','title contains "#1."','title contains "#2."','title contains "#3."','title contains "#4."','title contains "#5."','title contains "#6."','title contains "#7."'];
var ss = SpreadsheetApp.getActive(); //current spreadsheet
var directParents = DriveApp.getFileById(ss.getId()).getParents(); // folderIterator "targets" parent folder
var folder = directParents.next(); //accesses parent folder
var names =[]; //array that stores names of the spreadsheets found in folder in the order of the array variable searchFor
var fileIds=[]; //array that stores the IDs of the spreadsheets found in folder in the order of the array variable searchFor
for (var i=0; i<searchFor.length; i++) { //forLoop that goes through the searchFor array
var files = folder.searchFiles(searchFor[i]); //creates file iterator t
while (files.hasNext()) { //while loop goes through all the files that match searchFor variable
var file = files.next(); //
var fileId = file.getId(); // To get FileId of the file
fileIds.push(fileId); //
var name = file.getName(); //To get name of the file
names.push(name); //
}
}
for (var i=1; i<fileIds.length;i++) {
const formula = 'IMPORTRANGE("'+fileIds[i]+'";"#'+i+'!JJ188:JX188")'; //tak
var rownumber = 265+i;
Logger.log(rownumber);
ss.getSheetByName('Cal').getRange('C'+rownumber+'').setFormula(formula);
Logger.log(formula);
}
}
PS: Most of this is not my code but edited code I found somewhere on this board, youtube or wherever and edited it to fit my purpose.
From the question
Tl;Dr: Is there an easy way to use find and replace via GAS to just change the id part of the importrange formulas after duplicating spreadsheets?
There are several ways to replace the first argument (id / key / url) on IMPORTRANGE functions by using Google Apps Script. Perhaps the easier is to use Class TextFinder as it has several methods that might be helpful like:
matchFormulaText(matchFormulaText)
replaceAllWith(replaceText)
useRegularExpression(useRegEx)
I am creating a sheet that can create a series of sheets that interact to help run a simulation. Part of this project involves creating a series of sheets- individual score sheets- that can only be accessed by single players in the game. The code I'm hoping to use is below, but I'm running into a series of issues. The first is thatit says I don't have permission to run SpreadsheetApp.create. I have spent about an hour looking around online for how to cure this, but just don't understand it and can't find a good answer. The second, and potentially broader issue, is that it seems incredibly complicated to use GAS to interact with different spreadsheets (i.e. not within the same spreadsheet). At a later point in the project, we will have to retrieve information from these sheets, etc. and if it is going to be difficult to do through scripts, may have to think of a workaround.
/** #OnlyCurrentDoc */
function individualSheets(){
var playerarray = playerArray();
var spreadsheet = SpreadsheetApp.getActive();
var spreadsheetlinks = []
//creates individual sheet for each player, then adds the link of their sheet to a list
for(i=0;i<playerarray.length;i++){
var spreadsheetname = playerarray[i];
var newspreadsheet = SpreadsheetApp.create(spreadsheetname);
spreadsheetlinks.push(DriveApp.getUrl(newspreadhseet));
}
//pasting the links of each player in the appropriate sheet
for(i=0;i<spreadsheetlinks.length;i++){
spreadsheet.setActiveSheet("PlayerInfo").getRange('D'+(i+1)).activate()
spreadsheet.getCurrentCell.setValue(spreadhseetlinks[i])
}
}
Apps Script doesn't have difficulty to use several Spreadsheets in the same script.
I would add another array to store the Ids, so you won't have to get them from the urls:
var spreadsheetlinks = []
var spreadsheetIds = [];
//creates individual sheet for each player, then adds the link of their sheet to a list
for(i=0;i<playerarray.length;i++){
var spreadsheetname = playerarray[i];
var newspreadsheet = SpreadsheetApp.create(spreadsheetname);
spreadsheetlinks.push(DriveApp.getUrl(newspreadhseet));
spreadsheetIds.push(newspreadsheet.getId);
}
You can open the Spreadsheets using openById, so you can use an unlimited amount of them:
var sprSheet1 = SpreadsheetApp.openById('id 1');
var sprSheet2 = SpreadsheetApp.openById('id 2');
var sprSheet3 = SpreadsheetApp.openById('id 3');
...
or even better:
var sprSheets = [];
for (var j = 0; j < spreadsheetIds.length; j++){
sprSheets.push(SpreadsheetApp.openById(spreadsheetIds[j]);
}
Regarding the SpreadsheetApp.create issue, make sure you authorized the needed scopes:
Scripts that use this method require authorization with one or more of
the following scopes:
https://www.googleapis.com/auth/spreadsheets.currentonly
https://www.googleapis.com/auth/spreadsheets
You can check them in Apps Script View > Manifest file. If you never touched this, they won't show up. You can add them manually:
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file"
]
In case you still get the permission issue when creating the Spreadsheet, you might want to check the playerArray function to see if it's actually returning a String.
I'm trying to programmatically create a trigger for a Google Spreadsheet when a form is submitted with code from another Spreadsheet, but it won't work. Here is my code:
function createOnFormSubmitTrigger()
{
//Id of "Spreadsheet 1"
var ssId = "18bq-67nP4y7F9Hp4jzpbKPCyAsR6hglgcfmxCi_zj14";
ScriptApp.newTrigger("formInput").forSpreadsheet(ssId).onFormSubmit().create();
}
If I put that method into "Spreadsheet 1" and run it, it works fine and creates the script in Spreadsheet 1 as intended. However, if I put that method into say "Spreadsheet 2" and run it, it creates the trigger in Spreadsheet 2 instead of Spreadsheet 1, which is not as intended. What am I doing wrong?
Here is the code for formInput for the original script and the dummy script I made for testing:
Original:
function formInput()
{
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var inSheet = spreadSheet.getSheetByName("Form Responses");
var data = inSheet.getSheetValues(2,2,1,7);
var minutes = data[0][0];
var seconds = data[0][1];
var numMissed = data[0][2];
var sgIncorrect = data[0][3];
var sfMissed = data[0][4];
var year = data[0][5];
var testLevel = data[0][6];
var date = new Date();
var outSheet = spreadSheet.getSheetByName(testLevel);
var testLevelExists = (outSheet != null);
if(testLevelExists)
{
outSheet.insertRowBefore(2);
outSheet.getRange(2,1).setValue(date.getMonth()+1+ "/" + date.getDate());
outSheet.getRange(2,2).setValue(year);
var secStr = ("0" + seconds);
outSheet.getRange(2,3).setValue(minutes + ":" + secStr.substring(secStr.length-2));
outSheet.getRange(2,4).setValue(numMissed);
outSheet.getRange(2,5).setValue(sgIncorrect);
outSheet.getRange(2,6).setValue(sfMissed);
outSheet.getRange(2,7).setValue(350-7*(sgIncorrect+numMissed)-2*(sfMissed));
shiftBox(outSheet);
setFormulas(outSheet);
updateAverageTime(outSheet);
inSheet.deleteRow(2);
copyToMaster(spreadSheet,outSheet);
}
}
Dummy:
function formInput()
{
var hi = "hello";
}
I'd like to thank #JSmith for all his help first of all. I seemed to have misunderstood the creation of new triggers using the ScriptApp API. When the script is created, it links the trigger to actions performed on the target sheet, but the code must be in the original sheet which created the trigger. The trigger is also only displayed on the sheet which created the trigger.
As seen together,
try all your functions from google's IDE once.
Also it seems a trigger created from a certain spreadsheet is viewable from the trigger menu of the original spreadsheet script even if this trigger is linked to another spreadsheet.
I am trying to write a Google apps script that will allow me to use a Google sheet. I would like the app to read the data on the sheet, and then output a table into my Google site. I also want to be able to select which columns I want displayed on the Google site. I cannot use Awesome Tables because my Google Drive has sensitive client information -- so I do not want to grant access to Awesome Table. (My goal to create something like the "awesome table" People Directory without using that app). I have been researching for the last two days - and I realize I probably have to write my own Google app script. Problem is I'm not that proficient in JavaScript yet. So, the code below is what I have come up with - but I am getting this error:
TypeError: Cannot call method "getDataRange" of null. (line 4, file "Code", project "App Script for Employee Page")
Also, I tried using Debugger -- to me it looks like it is creating an array with my data, but I can't see the problem.
Why is this not working? Can anyone send me to where there is a template to help me read data off a Google sheet and display to my specifications (certain columns etc)?
function doGet(){
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
var JSONString = JSON.stringify(data);
var JSONOutput = ContentService.createTextOutput(JSONString);
JSONOutput.setMimeType(ContentService.MimeType.JSON);
return JSONOutput
}
}
You need to specify which spreadsheet you are accessing:
Like so:
var ss = SpreadsheetApp.openById("Your Sheet ID here")
Then you will access the specific sheet/tab in your spreadsheet like so:
var sheet = ss.getSheetByName("Name of your Sheet");
Note you will have to substitute "Your Sheet ID here" and "Name of your Sheet" to your sheet ID and sheet name respectively for the code to work. For more information on the function used above visit google apps script reference page
Complete code below:
function doGet(){
var ss = SpreadsheetApp.openById("Your Sheet ID here")
var sheet = ss.getSheetByName("Name of your Sheet");
var data = sheet.getDataRange().getValues();
for (var i = 0; i < data.length; i++) {
var JSONString = JSON.stringify(data);
var JSONOutput = ContentService.createTextOutput(JSONString);
JSONOutput.setMimeType(ContentService.MimeType.JSON);
return JSONOutput
}
}
Hope that helps
I am new in google apps script. I need help for creating new spreadsheet by using existing spreadsheet and copy and sort the data into newly created spreadsheet using google apps script. Can anyone help me?
this does the trick:
function copySpreadSheet(newSpreadSheetName) {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var data = sheet.getSheetValues(1, 1, 1000, 26);
var newSheet = SpreadsheetApp.create(newSpreadSheetName)
newSheet.getSheetByName("Sheet1")
.getRange(1,1,1000,26).setValues(data);
}
function main() {
copySpreadSheet("some_Spreadsheet");
}
After executing main, you can find the new spreadsheet in your drive file list. If you want to change the range of the data that should be copied, adjust the getSheetValues() method like this: getSheetValues(startRow, startColumn, numRows, numColumns). Don't forget to do the same for the getRange method a few lines below, otherwise you will get an error.
You can use this simpler code:
function copySpreadSheet() {
var s = SpreadsheetApp.openById("id");
var destination = DriveApp.getFolderById("idOfFolder");
DriveApp.getFileById("id_ofFile").makeCopy("New name", destination);
}
This will create a copy of your file in a new destination.
The SpreadsheetApp#spreadsheet class has a method copy:
var wb = SpreadsheetApp.getActiveSpreadsheet();
var new = wb.copy("Copy of " + wb.getName());
This copy method copies the current spreadsheet and returns a reference to the new one, so additional tasks (such as removing unneeded sheets, formatting ranges, adding additional values, etc.) can be performed.