Hello I wrote a small script to copy one template sheet in a spreadsheet, as a new sheet in the same spreadsheet.
I wrote two versions of it, one driven by a menu that asks for the name of the new sheet to be created:
function addonenewSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var temp = ss.getSheetByName('template');
var naame = Browser.inputBox("CustomerID to be created");
try {
ss.setActiveSheet(ss.getSheetByName(naame));
}
catch (e) {
ss.insertSheet(naame, {template:temp});
}
}
This one works as intended, and names the new sheet 234 if I say so in the inputbox.
The second function is very similar, but parses some values and attempts to create many sheets at once:
function addmissingSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var temp = ss.getSheetByName('template');
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 10; i < data.length; i++) {
if(typeof data[i][1] == 'number'){
try {
ss.setActiveSheet(ss.getSheetByName(data[i][1]));
}
catch (e) {
Logger.log('Customer ID: ' + data[i][1]);
var insertpage = data[i][1];
ss.insertSheet(insertpage, {template:temp});
}
}
}
}
As long as Logger.log is concerned, data[i][1] has the right value, but somehow insertSheet creates sheets named "copy of template", "copy of template 2"... Instead of taking the value assigned in data[i][1]
Would anyone know why this behaviour and how I can solve this issue?
your second script does not use correct variable types. The method you are using insert sheet uses types (<string>, {template:<sheet>}). Since your customer ID is a number it does not work. There is a simple fix you can do
Change
var insertpage = data[i][1];
into:
var insertpage = data[i][1].toString();
and you will now be able to use the customer ID (which is a number) to create a sheet name (which is a string)
Related
I've created a spreadsheet that I'd like to separate based on the data found in one particular cell. The main spreadsheet has a column that indicates either "tardy, discipline, reinforcement." I'd like to move "tardy" and "reinforcement" into their own spreadsheets. Additionally, I'd like "tardy" and "reinforcement" lines to be removed, once in the appropriate sheet. This should give me a total of three spreadsheets.
I've used a script before that was working and moving my tardy lines onto a different spreadsheet. However, for whatever reason, I am not getting an error that says "TypeError: Cannot read property 'length' of undefined (line 19, file "Code").
I've been playing around with this and it's likely I've messed something up. I have no experience coding but I'm trying my best to figure this out. Currently, the script I have is below. Any help would be greatly appreciated.
function copyrange() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Minor Infractions - Current'); //source sheet
var testrange = sheet.getRange('O:O'); //range to check
var testvalue = (testrange.getValues());
var csh = ss.getSheetByName('Tardies - Current'); //destination sheet
var data = [];
var j =[];
//Condition check in O:O; If true copy the same row to data array
for (i=0; i<testvalue.length;i++) {
if ( testvalue[i] == 'Tardy') {
data.push.apply(data,sheet.getRange(i+1,1,1,25).getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
//Delete matched rows in the source sheet
for (i=0;i<j.length;i++){
var k = j[i]+1;
sheet.deleteRow(k);
//Alter j to account for deleted rows
if (!(i == j.length-1)) {
j[i+1] = j[i+1]-i-1;
}
}
}
as this answer says, you could accomplish this with a function:
=sort(importrange("spreadsheetURL", "Sheet1!A2:AA10000"),sort_col#,TRUE/FALSE,[sort_col2#],[TRUE/FALSE]...)
keep in mind this function is a guide, you can't just copy and paste, you have to fill out the values
Try this:
function copyrange() {
const ss=SpreadsheetApp.getActive();
const sheet=ss.getSheetByName('Minor Infractions - Current');
const testrange=sheet.getRange(1,15,sheet.getLastRow());
const testvalue=testrange.getValues();
const csh=ss.getSheetByName('Tardies - Current');
let data=[];
let d=0;
for (let i=0;i<testvalue.length;i++) {
if (testvalue[i]=='Tardy') {
data.push(sheet.getRange(i+1,1,1,25).getValue());
sheet.deleteRow(i+1-d++);
}
}
csh.getRange(csh.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
I have this spreadsheet and I would like to copy the template in a directory for each month and add the link in each corresponding cell, adding the corresponding data
Now I do it adding new sheets but I wanted to organize by directories for each month.
It's possible?
Thanks
https://docs.google.com/spreadsheets/d/1abdggD73Zb0XmRoFaMx0ssULjtLLTHhFQV3ikbaEK_I/edit?usp=sharing
function newSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var templateSheet = ss.getSheetByName("Plantilla")
var sheet1 = ss.getSheetByName("Sheet1")
var getNames = sheet1.getRange("G2:G").getValues().filter(String).toString().split(",");
for (var i = 0; i < getNames.length; i++) {
var copy = ss.getSheetByName(getNames[i]);
if (copy) {
Logger.log("Sheet already exists");
} else {
templateSheet.copyTo(ss).setName(getNames[i]);
ss.setActiveSheet(ss.getSheetByName(getNames[i]));
ss.moveActiveSheet(ss.getNumSheets());
}
}
}
// function to create the index
function createIndex() {
// Get all the different sheet IDs
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var namesArray = sheetNamesIds(sheets);
var indexSheetNames = namesArray[0];
var indexSheetIds = namesArray[1];
// check if sheet called sheet called already exists
// if no index sheet exists, create one
if (ss.getSheetByName('index') == null) {
var indexSheet = ss.insertSheet('Index',0);
}
// if sheet called index does exist, prompt user for a different name or option to cancel
else {
var indexNewName = Browser.inputBox('The name Index is already being used, please choose a different name:', 'Please choose another name', Browser.Buttons.OK_CANCEL);
if (indexNewName != 'cancel') {
var indexSheet = ss.insertSheet(indexNewName,0);
}
else {
Browser.msgBox('No index sheet created');
}
}
// add sheet title, sheet names and hyperlink formulas
if (indexSheet) {
printIndex(indexSheet,indexSheetNames,indexSheetIds);
}
}
// function to update the index, assumes index is the first sheet in the workbook
function updateIndex() {
// Get all the different sheet IDs
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var indexSheet = sheets[0];
var namesArray = sheetNamesIds(sheets);
var indexSheetNames = namesArray[0];
var indexSheetIds = namesArray[1];
printIndex(indexSheet,indexSheetNames,indexSheetIds);
}
// function to print out the index
function printIndex(sheet,names,formulas) {
sheet.clearContents();
sheet.getRange(1,1).setValue('Workbook Index').setFontWeight('bold');
sheet.getRange(3,1,names.length,1).setValues(names);
sheet.getRange(3,2,formulas.length,1).setFormulas(formulas);
}
// function to create array of sheet names and sheet ids
function sheetNamesIds(sheets) {
var indexSheetNames = [];
var indexSheetIds = [];
// create array of sheet names and sheet gids
sheets.forEach(function(sheet){
indexSheetNames.push([sheet.getSheetName()]);
indexSheetIds.push(['=hyperlink("#gid='
+ sheet.getSheetId()
+ '";"'
+ sheet.getSheetName()
+ '")']);
});
return [indexSheetNames, indexSheetIds];
}
Solution
With the use of the Drive service in Apps Script and Spreadsheet service you can easily achieve your intentions. The following is the self explanatory commented piece of code that achives what you are aiming for.
NOTE : I have only made an example of how it would be with the first month (ENERO) as to achive the rest it would just be copying what I did with the first month.
function myFunction() {
// Get the sheet where we have all the dates
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
// Get the month name. Repeat this for the other months you might want to include
// For example if February is on A10 just get the range from A10
var Month1 = sheet.getRange('A1').getValue();
// Create a parent folder in the root of your drive where you will be storing everything for this project
var parentFolder = DriveApp.createFolder('Months');
// Create a folder for each month using the name we got before. Repeat for the rest of the months.
var Month1Folder = DriveApp.getFolderById(parentFolder.getId()).createFolder(Month1);
// Get the dates of each month. Repeat for the rest of the months.
// For example, if February dates go from A11 to A21 get the range A11:A21
// Also, getValues returns an array of arrays. Therefore I have flatten it to make a simple 1D array
var Month1Days = sheet.getRange('A2:A4').getValues().flat();
// For every element of our Month 1 date names array
// Repeat this block for the rest of the months substituying the array and column (to not overwrite) accordingly
for(i=0;i<Month1Days.length;i++){
// Create a new spreadsheet with the name of the dates of that month and get its id
var idFile = SpreadsheetApp.create(Month1Days[i]).getId();
// Get the file object of the new Spreadsheet
var file = DriveApp.getFileById(idFile);
// Add this file to our month folder
Month1Folder.addFile(file);
// Remove the duplicate that is still in the root folder
DriveApp.getRootFolder().removeFile(file);
// Paste a link to this new spreadsheet in our original sheet in the third column
sheet.getRange(i+1, 3).setValue(file.getUrl());
}
}
I hope this has helped you. Let me know if you need anything else or if you did not understood something. :)
I have the results of a google form (a google spreadsheet). I would like to write an app script to check each column for a string "YES." If the column has that string, then I would like to change the background color of that column (or one cell in that column) green. The number of columns will vary each time the form is sent so it would need to check all columns used (Sorry, I mean I send out a similar form each time and want to use the same script on each one, except that each time the form is used it can come back with a different number of columns-responses - thanks corn3lius). Can this be done in a google form response spreadsheet? Here is the code I am playing with. (updated code with Cooper's input)
function colchk(){
var ss = SpreadsheetApp.getActiveSheet();
var resp = ss.getDataRange().getValues();
for(var n=0;n<resp.length;n++)
{
for(var p=0;p<resp[n].length;p++)
{
if(resp[n][p].toString().match(/^YES/)){ ss.getRange(n+1,p+1).setBackground('#00ff00')}}};
}
//this code works...Thanks Cooper!
This is an older post, but I'd like to leave an easier solution here for any future visitors:
function colorYesCells() {
var sheet = SpreadsheetApp.getActiveSheet();
var yesFinder = sheet.createTextFinder("YES");
var yesCells = yesFinder.findAll();
yesCells.forEach(function(cell){
cell.setBackground('#00ff00');
});
};
Try this:
if(resp[n][0].toString().match(/^YES/){ ss.getRange(n+1,1).setBackground('#00ff00') };
Perhap's something like this:
function colchk(){
var ss = SpreadsheetApp.getActiveSheet();
var resp = ss.getDataRange().getValues();
for(var n=0;n<resp.length;++n)
{
for(var p=0;p<resp[n].length;p++)
{
if(resp[n][p].toString().match(/^YES/){ ss.getRange(n+1,p+1).setBackground('#00ff00') };
}
};
Since I can't comment, I write here :
for(var n=0;n<resp.length;++n)
should be :
for(var n=0;n<resp.length;n++)
++n --> n++
typing too fast ?
based off #coopers code- small edits
function colchk(){
var ss = SpreadsheetApp.getActiveSheet();
var resp = ss.getDataRange().getValues();
for(var n=0;n<resp.length;n++)
{
for(var p=0;p<resp[n].length;p++)
{
if(resp[n][p].toString().match(/^YES/)) {
ss.getRange(n+1,p+1).setBackground('#00ff00') };
}
}};
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
}
}
}
I tried to get the value of a range and than remove all points from the cell.
var FILE = SpreadsheetApp.openById("xyz");
var CONTENT = FILE.getSheetByName("Sheet1");
var A1 = CONTENT.getRange("I17").getValue();
A1. replace(".", "");
It gives me that can't find the replace function. Is there any function in Google Apps Script that allows me to replace the string?
If this is an exact copy of your script then you have a space in-between A1. and replace but I assume it is not.
#SergeInsas is right the content needs to be a string for the replace() function to work, so if your trying to replace the . in a decimal number then you can use the toString() method first like below.
var FILE = SpreadsheetApp.openById("xyz");
var CONTENT = FILE.getSheetByName("Sheet1");
var A1 = CONTENT.getRange("I17").getValue();
var A1String = A1.toString().replace(".", "");
Or you can multiply the number to get rid of the decimal but this will depend on how many decimal places you have :)
There is a more powerful, and simpler, method available: TextFinder.
The accepted answer to this question requires an additional step to post the replaced string back to the cell.
The TextFinder method does not need you to write the data back to the cell.
And if you want to search multiple cells, then this method saves you the iterations.
var FILE = SpreadsheetApp.openById("xyz");
var CONTENT = FILE.getSheetByName("Sheet1");
var A1 = CONTENT.getRange("I17");
A1.createTextFinder(".").replaceAllWith("");
I haven't tested it on a large data set but I suspect this would be quite quick.
Edit: I wrote a short tutorial on this.
For some reason, this solution doesn't work for me. Here is my whole code that should replace the '+' symbol with 'nothing'
// I need to replace more occurrences of different strings, so this is just an example..
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange("G5:G7").getValues();
// this is a loop, to go through multiple cells that may contain the text, that needs to be replaced.
for (var i = 0 ; i<range.length ; i++) {
var le = range.length;
var stri = range[i].toString().replace("+", "");
Logger.log(stri);
}
var msg = ui.alert("Replaced?");
return msg;
Hope this help you
function removeAccents() {
var spreadsheet = SpreadsheetApp.getActive();
var range = spreadsheet.getRange("F3:F");
var data = range.getValues();
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
data[row][col] = (data[row][col]).toString().replace(/é/g, 'e');
data[row][col] = (data[row][col]).toString().replace(/ã/g, 'a');
}
}
range.setValues(data);
};
Sharing a very helpful solution from Bannager Bong on this Google Docs Editor Help Forum thread. Made a slight modification to the function so that it accepts arguments for the find, replace values and then added a range argument so that the function can target a specific region. Even so, this method is extremely slow (my sheets have 5k rows).
function Cleanup12m() {
var spreadsheet = SpreadsheetApp.getActive();
//fandr(",", "");
//fandr("\"","");
fandr("�","",spreadsheet.getRange('BA:BA')); //uses specific range
};
function fandr(find, repl) {
var r=SpreadsheetApp.getActiveSheet().getDataRange();
var rws=r.getNumRows();
var cls=r.getNumColumns();
var i,j,a,find,repl;
//find="abc";
//repl="xyz";
for (i=1;i<=rws;i++) {
for (j=1;j<=cls;j++) {
a=r.getCell(i, j).getValue();
if (r.getCell(i,j).getFormula()) {continue;}
//if (a==find) { r.getCell(i, j).setValue(repl);}
try {
a=a.replace(find,repl);
r.getCell(i, j).setValue(a);
}
catch (err) {continue;}
}
}
};
//Revised to apply to a selected range
function fandr(find, repl, range) {
var r= range;//SpreadsheetApp.getActiveSheet().getDataRange();
var rws=r.getNumRows();
var cls=r.getNumColumns();
var i,j,a,find,repl;
//find="abc";
//repl="xyz";
for (i=1;i<=rws;i++) {
for (j=1;j<=cls;j++) {
a=r.getCell(i, j).getValue();
if (r.getCell(i,j).getFormula()) {continue;}
//if (a==find) { r.getCell(i, j).setValue(repl);}
try {
a=a.replace(find,repl);
r.getCell(i, j).setValue(a);
}
catch (err) {continue;}
}
}
};