I'm working in Google Sheets and I'm trying to create a script that will make a set number of copies of the current file, giving each copy the next name from a list of names in a range, and place those files in folders that were created by a previous script. I was able to get it all working, but only for the first file (out of 6, and possible far more) and can't figure out what I'm doing wrong.
Here's a copy of the sheet. I also have another version of this that works to just create copies of the document, but I'm trying to streamline the process for my end users who may be creating dozens of copies and was hoping that doing the organization for them would help.
Thanks for your help!
Here's the script:
function createcopies2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get the range of cells that store necessary data.
var CoachNames = ss.getRangeByName("CoachNames");
var CoachObjects = CoachNames.getValues();
var schoolNames = ss.getRangeByName("SchoolNames");
var SchoolObjects = schoolNames.getValues();
var id = ss.getId();
// The next variable gets a value that counts how many CoachNames there are in the spreadsheet
var coaches = ss.getRangeByName("Coaches");
var numcoaches = coaches.getValue();
//here's the function
for(i=0; i<numcoaches; i++){
var drive=DriveApp.getFileById(id);
var name=CoachObjects[i].toString();
var folder=DriveApp.getFoldersByName(SchoolObjects[i]).next();
var folderid=folder.getId();
var folder2=DriveApp.getFolderById(folderid)
if(folder) {
drive.makeCopy(name, folder2)}
else{
drive.makeCopy(name);
}
return;
}
}
You are on the right track.
I have modified you below, with explanation:
function createcopies2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// Get the range of cells that store necessary data.
var CoachNames = ss.getRangeByName("CoachNames");
//The below statements a 2D dimensional array.
//To access the individual value you will have a statement like this
//CoachObjects[0][0],CoachObject[1][0],[2][0] ..., down the row
var CoachObjects = CoachNames.getValues();
var schoolNames = ss.getRangeByName("SchoolNames");
//The below statements a 2D dimensional array.
var SchoolObjects = schoolNames.getValues();
var id = ss.getId();
// The next variable gets a value that counts how many CoachNames there are in the spreadsheet
var coaches = ss.getRangeByName("Coaches");
var numcoaches = coaches.getValue();
//Moved the below statement out of the loop
// Baceause you are using the same file
var drive=DriveApp.getFileById(id);
//here's the function
for(i=0; i<numcoaches; i++){
var name=CoachObjects[i][0].toString();
var folder=DriveApp.getFoldersByName(SchoolObjects[i][0]).next();
var folderid=folder.getId();
var folder2=DriveApp.getFolderById(folderid)
if(folder) {
drive.makeCopy(name, folder2)}
else{
drive.makeCopy(name);
}
return;
}
}
I modified the code since you get a 2D array from getValues
//The below statements a 2D dimensional array.
var CoachObjects = CoachNames.getValues();
To access the individual value you will use a statement like this
`CoachObjects[0][0]`
CoachObjects[1][0]
....... [2][0] ...
down the row
Also, These are redundant lines of code:
var folder=DriveApp.getFoldersByName(SchoolObjects[i][0]).next();
var folderid=folder.getId();
var folder2=DriveApp.getFolderById(folderid)
you can just replace it with
var folder2=DriveApp.getFoldersByName(SchoolObjects[i][0]).next();
Related
I've been looking on this website and others for an answer but can't find anything relevant and was wondering if someone could help please.
I've using Apps Script - Google Sheets.
The main sheet was called "M-Front". So it got quotation number with revision number. If new quotation, the revision will be zero. If we revise the quotation once, the revision number will be 1.
For example, GE-2108-0271-Rev.0 is new quotation.
If we revise once, it would be GE-2108-0271-Rev.1.
I have other sheet called "M-Items".
Let say for GE-2108-0271-Rev.0, we have three rows for that quotation number represent three items for that quotation.
My intention is , if new revision was made in "M-Front". It will be GE-2108-0271-Rev.1. But how to detect the last row from "M-Front" quotation number and in "M-Items" we copy and paste the rows. In this case, 3 rows/items. and make the quotation in "M-Items" from GE-2108-0271-Rev.0 to GE-2108-0271-Rev.1.
M-Front
M-Items
The Script i've stuck
function CopyRange() {
var sourcespread = SpreadsheetApp.openById('1Zgs1jzjIeaBpd5Ms7emQgxhVJBMtlEOlDNDfxlhSRiY'); //replace with source ID
var sourcesheet = sourcespread.getSheetByName('M-Front'); //replace with source Sheet tab name
var destspread = SpreadsheetApp.openById('1Zgs1jzjIeaBpd5Ms7emQgxhVJBMtlEOlDNDfxlhSRiY'); //replace with destination ID
var destsheet = destspread.getSheetByName('M-Items'); //replace with destination Sheet tab name
var testrange = sourcesheet.getRange('M:M').getLastRow;
var testvalue = (testrange.getValues());
var data = [];
var j =[];
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] /= 0) {
data.push.apply(data,sourcesheet.getRange('A:A').getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
destsheet.getRange(destsheet.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
You might want to try the below script:
function CopyRange() {
var sourcespread = SpreadsheetApp.openById('1Zgs1jzjIeaBpd5Ms7emQgxhVJBMtlEOlDNDfxlhSRiY'); //replace with source ID
var sourcesheet = sourcespread.getSheetByName('M-Front'); //replace with source Sheet tab name
var destsheet = sourcespread.getSheetByName('M-Items'); //replace with destination Sheet tab name
var mcol= sourcesheet.getRange('M1:M').getValues();
var acol = sourcesheet.getRange('A1:A').getValues();
var ccol = destsheet.getRange('C1:C').getValues();
var acol2 = destsheet.getRange('A1:A').getValues();
var mvalues = mcol.filter(String);
var avalues = acol.filter(String);
var cvalues = ccol.filter(String);
var avalues2 = acol2.filter(String);
for (let i=1; i<mvalues.length; i++) {
if (mvalues[i][0] != 0) {
if (avalues[i][0] == avalues2[i][0] && mvalues[i][0] == cvalues[i][0] - 1)
var valuescopy = sourcesheet.getRange("RANGE_FOR_THE_VALUES_TO_COPY").getValues();
destsheet.getRange("RANGE_WHERE_TO_PASTE").setValues(valuescopy);
cvalues[i][0]++;
}
}
}
It is important to note the following points:
getLastRow will return the last row for the entire range - this means that the rows which have no values are also included this;
In order to retrieve the rows which contain a value, the filter has been used.
getValues method will return a 2D array, so you will have to access an element in this way array[i][j].
Moreover, please bear in mind that you will have to adjust the ranges properly such that they match your needs accordingly; more specifically, the range from where you want to copy the values and also the destination range.
Reference
getLastRow();
getValues();
getRange(row, column, numRows, numColumns).
I am trying to copy data from 1 spreadsheet to another, I have successfully implemented something i found online that works with a specific range
function cloneGoogleSheet() {
// source doc
var sss = SpreadsheetApp.openById("spreadsheetkey1");
// source sheet
var ss = sss.getSheetByName('_tab_name_source');
// Get full range of data
var SRange = ss.getRange(7,3,5,1);
// get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
// get the data values in range
var SData = SRange.getValues();
// target spreadsheet
var tss = SpreadsheetApp.openById("spreadsheetkey2");
// target sheet
var ts = tss.getSheetByName('tab_name_destination');
// Clear the Google Sheet before copy
//ts.clear({contentsOnly: true});
// set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
};
The above piece coding work perfectly however I need to copy 18 different ranges that i cant just merge into 1 range. I considered the option of using the above however "multiplying" it 18 times for each range that however seems like a very inelegant solution.
I found a working solution that works if it stays within the same spreadsheet since it uses copyto instead of get/set values. The values part works perfectly since it doesnt mess with merge cells formatting. I have been struggling past 2-3 hours in merging the below-working code with elements from the first code to make a working script.
function test () {
try {
var spread = SpreadsheetApp.openById("spreadsheetkey");
var sheet = spread.getSheetByName("tab_name_source");
var rlist = sheet.getRangeList(["c7:c11", "g7:g11", "k7:k11"]);
sheet = spread.getSheetByName("tab_name_destination");
for( var i=0; i<rlist.getRanges().length; i++ ) {
var r1 = rlist.getRanges()[i];
var r2 = sheet.getRange(r1.getA1Notation());
r1.copyto(r2);
}
}
catch(err) {
Logger.log(err);
}
}
I tried initially to adapt the 2nd piece of coding to using setvalues however i had not been able to succesfully implement the part of getvalues within the scope of this code. I figured once I got this piece of code working with get and set values instead of Copyto i would only need to add the spreadsheetid of the other spreadsheet to get the final result
Try this:
function myFunction() {
var sourceSS = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = sourceSS.getSheetByName("sheetname");
var targetSS = SpreadsheetApp.openById("spreadsheet id here");
var targetSheet = targetSS.getSheetByName("Sheet1");
var ranges = ["C7:C11", "G7:G11", "K7:K11"];
ranges.forEach(range => {
var data = sourceSheet.getRange(range).getValues();
targetSheet.getRange(range).setValues(data);
})
}
Source sheet:
Destination sheet:
References:
setValues()
getValues()
This will only open F2 and will array that value down column G...help?
function CountData() {
var sheet = SpreadsheetApp;
var urlsheet = sheet.getActiveSpreadsheet().getSheetByName('Sheet1');
var url = urlsheet.getRange('F2:F100').getValues();
for(var i=0;i<url.length;++i){
var formsheet = sheet.openByUrl(url);
var CountRows = formsheet.getActiveSheet().getLastRow();
urlsheet.getRange('G2:G').setValue(CountRows);
}
};
You're looping through the array, but you're not using the actual value. Keep in mind that .getValues() returns a 2-dimensional array, so you need to access the value using [i][0].
function CountData() {
var sheet = SpreadsheetApp;
var urlsheet = sheet.getActiveSpreadsheet().getSheetByName('Sheet1');
var urls = urlsheet.getRange('F2:F100').getValues(); // Renamed to be plural, indicating some kind of list
for(var i=0;i<urls.length;++i){
var formsheet = sheet.openByUrl(urls[i][0]); // Select the URL
// ... the rest of your code
}
};
I think the rest of the code in your for-loop will have issues because
The script is not container-bound to formsheet, so you can't access .getActiveSheet(). Try something like .getSheetByName() instead.
You're not updating the range urlsheet.getRange('G2:G'), so you're going to be replacing the values in that column for every url.
function CountData() {
var ush=SpreadsheetApp.getActive().getSheetByName('Sheet1');
var uv=ush.getRange(2,6,99,1).getValues().map(function(r){return r[0];});
var rA=[];
uv.forEach(function(url){rA.push([SpreadsheetApp.openByUrl(url).getActiveSheet().getLastRow()])});
ush.getRange(2,7,rA.length,rA[0].length).setValues(rA);
}
In a google script I have written something to check my monthly expenses, which are listed in a google sheet.
Based on words the script finds, every line gets a category tag. It works fine, but the number of words to search for is getting big. And the array is getting big too.
I have listed 6 pairs (words to find, tag to add) - but in real version I have as many as 35. How can I create the pairs, and load everything automatically in the array?
This is my script:
function myFunction() {
// check usual suspects
var A1 = ["CAFE", "HORECA"]
var A2 = ["ALBERT", "AH"]
var A3 = ["VOMAR","Vomar"]
var A4 = ["HEMA","HEMA"]
var A5 = ["KRUID","Drogist"]
var A6 = ["RESTA", "Horeca"]
// in Array
var expenses = [A1,A2,A3,A4,A5,A6]
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues(); // read all data in the sheet
for (i in expenses)
{for(n=0;n<data.length;++n){ // iterate row by row and examine data in column A
if(data[n][3].toString().toUpperCase().match(expenses[i][0])==expenses[i][0]){ data[n][4] = expenses[i][1]};
// if column D contains 'xyz' then set value in index [5] (is column E)
}
Logger.log(data)
ss.getRange(1,1,data.length,data[0].length).setValues(data); // write back to the sheet
}
}
I can propose you that:
function multiPass(){
var searchCriterions = [
["CAFE","HORECA" ],
["ALBERT", "AH"],
["VOMAR","Vomar"],
["HEMA","HEMA"]
];
var dico = {};
var patt = "";
for (var i in searchCriterions) {
dico[searchCriterions[i][0]] = searchCriterions[i][1];
patt += "("+searchCriterions[i][0]+")";
if((Number(i)+1)<searchCriterions.length){
patt += "|";
}
}
var re = new RegExp(patt,"");
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues(); // read all data in the sheet
Logger.log(re);
for(n=0;n<data.length;++n){ // iterate row by row and examine data in column A
// THAT'S NOT COLUMN "A", 3 --> "D"
var test = data[n][3].toString().toUpperCase().match(re);
Logger.log(test);
if(test!==null){
data[n][4] = dico[test[0]]
};
}
ss.getRange(1,1,data.length,data[0].length).setValues(data); // write back to the sheet
}
instead of using variable for your "pairs" prefer to use a big table (it's less painfull to write)
then transform your pairs in object to quickly access the second argument of the pair and create a big regexp that check at once all the keywords instead of parsing them one by one.
Now as we are using a big array as search criterions we can totally imagine that this big array is loaded instead of hard coding it. If you have a sheet where the data is you can change the code this way:
var searchCriterions = SpreadsheetApp.getActive().getRange("namedRange").getValues();
I need some help refining this code. It should copy a specific worksheet in this case the sheet Master Copy based on the rows on the sheet Maxes. Then rename the sheet to the name on the given row in the sheet Maxes. When I try to execute the code all it does is insert a blank page and adds it to the end of the Spreadsheet. Please forgive the poorly written code I am really new at this and trying to make something work. Any suggestions that you could give would be gratefully appreciated. I'm not sure if there is an error within the while loops or what exactly.
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A300");
var nameStartRow = nameSource.getRange("A2");
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("a1:m66");
var nameEndRow = nameSource.getLastRow();
var lifterName;
while (nameStartRow <= nameEndRow)
{
lifterName = nameSource.getCell(nameStartRow, nameColumn);
if (lifterName == null)
{
errors.clear();
ss.getSheetsByName(lifterName) = lifterName;
if(errors.number() > 0)
{
errors.clear();
var newSheet = ss.insertSheet();
ss.renameActiveSheet(lifterName);
ss.getSheetByName(lifterName);
trainingRange.copyValuesToRange(lifterName,1,1,16,66);
lifterName.copyValuesToRange(lifterName,4,1,4,1);
}
} nameStartRow = nameStartRow + 1;
}
}
I modifyed your code because I didn't understood what you wanted exactlly, I hope this will do the trick:
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A").getValues(); // it's a table of table [][]
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("A1:M66").getValues(); // get values give a table of table
for(var i in nameColumn){
if(nameColumn[i][0]!=""){ // if blank we skip
try{ // try to see if already exist who know...
var lifter = ss.getSheetByName(nameColumn[i][0]).activate();
Logger.log("getting lifter sheet "+nameColumn[i][0]);
}
catch(err){ // well it didn't exist so lets create it :D
var lifter = ss.insertSheet(nameColumn[i][0]);
Logger.log("creating lifter sheet "+nameColumn[i][0]);
}
SpreadsheetApp.flush();
lifter.getRange("A1:M66").setValues(trainingRange); // passing the value to the created sheet
}
}
}
I also have a demo sheet here.
Please tell me if this is what you wanted (if not can you give a demo sheet of what you want and what you should get at the end)
EDIT
here the script with formulas copy (it's not nice because you are forced to define in the script where your formulas are, we could have the script to analyse the spreadsheet to search the formulas, but, has it's a copy from template, it's less ressource consuming not to do so.)
function createWorkouts(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var nameSource = ss.getSheetByName("Maxes");
var nameColumn = nameSource.getRange("A2:A").getValues(); // it's a table of table [][]
var trainingSheet = ss.getSheetByName("Master Copy");
var trainingRange = trainingSheet.getRange("A1:H21").getValues(); // get values give a table of table
var trainingFormulasD = trainingSheet.getRange("D2:D21").getFormulas(); // get the formulas to copy
var trainingFormulasH = trainingSheet.getRange("H2:H21").getFormulas(); // get others formulas to copy
for(var i in nameColumn){
if(nameColumn[i][0]!=""){ // if blank we skip
try{ // try to see if already exist who know...
var lifter = ss.getSheetByName(nameColumn[i][0]).activate();
Logger.log("getting lifter sheet "+nameColumn[i][0]);
}
catch(err){ // well it didn't exist so lets create it :D
var lifter = ss.insertSheet(nameColumn[i][0]);
Logger.log("creating lifter sheet "+nameColumn[i][0]);
}
SpreadsheetApp.flush();
lifter.getRange("A1:H21").setValues(trainingRange); // passing the value to the created sheet
lifter.getRange("D2:D21").setFormulas(trainingFormulasD); //passing formulas
lifter.getRange("H2:H21").setFormulas(trainingFormulasH); //passing formulas
}
}
}