I am hoping that someone might be able to help me out, I've been doing a lot of searching in the past few days and coming up short of a solution. Likely has to do with my lack of knowledge on coding... I know enough to be dangerous, just not enough to be effective or efficient!
To start, here is my goal.
To create a document, that will contain a 'master list' of tasks for my marketing team.
Each team member (currently 4) will have their own tab, which would only display tasks assigned to their name & have blank spaces under both 'completed' and 'canceled' columns...
In addition to the team member tabs, there would be two others, 'Completed' and 'Canceled'. These tabs would contain any tasks, by any team member, that have a date under the respective column.
Currently, I managed to create a script that will delete all tabs (other than the master list) and recreate them with the assigned name. What I haven't been able to do is get each sheet to filter results. I can't seem to get any code that I've found in the forums to work. Nothing will filter the results automatically on any tab, it only copies the master list and renames the tabs. Can someone point me in the right direction?
Am I going about this in the most efficient way possible? Do I need a button that will run the script on command? Is there a way for the 'team member' sheets to update live based on what is entered into the master list? I tried to utilize this information (Filter data by column K in Google Script Editor (Google Sheets)) but was not able to make it function within my document.
Sorry for the lengthy, post, thanks in advance for any and all help!
A copy of the original file:
https://docs.google.com/spreadsheets/d/141JochDYmt9RHRnyaY2iIoyAISCNNXFVUvEtJlBwtiQ/edit?usp=sharing
Example of the code:
function RunFilters() {
var name = "Adam";
/*ADAM*/
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Marketing').copyTo(ss);
/* Before cloning the sheet, delete any previous copy */
var old_name = ss.getSheetByName(name);
if (old_name) ss.deleteSheet(old_name); // or old.setName(new Name);
SpreadsheetApp.flush();
sheet.setName(name);
/* Make the new sheet active */
ss.setActiveSheet(sheet);
function myFunction() {
var ss = SpreadsheetApp.getSheetByName('Marketing'); //replace with source Sheet tab name
var range = ss.getRange('A:I'); //assign the range you want to copy
var data = range.getValues();
var tss = SpreadsheetApp.getActiveSpreadsheet(); //replace with destination ID
var ts = tss.getSheetByName('Adam'); //replace with destination Sheet tab name
ts.getRange(ts.getLastRow() + 1, 1, data.length, data[0].length).setValues(data);
var range = ts.getRange(ts.getLastRow() + 1, 1, data.length, data[0].length)
var rawData = range.getValues() // get value from spreadsheet 2
var data = [] // Filtered Data will be stored in this array
for (var i = 0; i < rawData.length; i++) {
if(rawData[i][5] == "Adam") // Check to see if column K says ipad if not skip it
{
data.push(rawData[i])
}
}
}
}
Related
In my ongoing efforts to come to grips with google scripts:
I am trying to loop through a list of items in a sheet - wherever there is a "X" in column A, I want to copy my active file and then save the URL of the new file into my active file. I've figured out most of it with the help of my second brain (otherwise known as google) and a helpful person on this forum, but I'm stuck on how to get the URL of the new file and save it to my sheet. While I'm at it, I'd also like to save the current date into column B of the same sheet. Here is the code so far:
function LoopSaveSend() {
var activeSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("4 Week Cycle");
var lastRow = activeSheet.getLastRow();
var lastCol = activeSheet.getLastColumn();
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Log");
var lastSourceRow = sourceSheet.getLastRow();
var lastSourceCol = sourceSheet.getLastColumn();
var sourceRange = sourceSheet.getRange(1, 1, lastSourceRow, lastSourceCol);
var sourceData = sourceRange.getValues();
var activeRow = 0;
//Loop through every retrieved row from the Source
for (row in sourceData) {
//IF Column A in this row has 'X', then work on it.
if (sourceData[row][0] == 'X') {
//Save it to a temporary variable
var tempvalue = [sourceData[row][2]];
activeSheet.getRange('rfInitials').setValue(tempvalue);
var spreadsheet = SpreadsheetApp.getActive();
var rffilename = spreadsheet.getRange('rfFileName').getValue();
spreadsheet.copy(rffilename);
var url = SpreadsheetApp.openById(rffilename).getUrl();
sourceData[row][4].setValue(url);
sourceData[row][0].setValue("")
}
}
}
It's the last 3 lines that aren't working (I don't even know if the last 2 rows will work because I haven't got that far yet.) The error I'm getting is that I need permission to open the file - but actually I don't want to open it - just want to get the URL. Also - no code for getting the date yet... baby steps and all that.
Any assistance greatly appreciated.
To get the URL of the newly copied spreadsheet, change these two lines:
spreadsheet.copy(rffilename);
var url = SpreadsheetApp.openById(rffilename).getUrl();
to this single line:
var url = spreadsheet.copy(rffilename).getUrl()
The key here is that, per the documentation, the copy method
Copies the spreadsheet and returns the new one.
So you can call .getUrl() directly on the result of copy to get the URL of the new copy.
The reason this line doesn't work as written:
var url = SpreadsheetApp.openById(rffilename).getUrl();
is that rffilename is not a file id, it's a file name. To use .openById you would need to know the file id of the new copy (which you could get with spreadsheet.copy(rffilename).getId() but in this case you don't need to).
You will also find that your last two lines don't work, as .setValue is a method of the Range object. You'll need to change these to something like
activeSheet.getRange(row,4).setValue(url);
activeSheet.getRange(row,0).setValue("")
I'm attempting to write a script to continuously update two spreadsheets so that the information put in one always goes into the other.
The full project is to create a master spreadsheet with 50 people on it and each one of them has their own sheet/page, however they aren't allowed to access this master sheet as they are not allowed to see the other peoples data. (I am currently unaware of any viewing permission commands but I'm pretty sure there aren't any).
So the solution that I have been considering is creating 50 other spreadsheets and each of them will have a single sheet with all of the same information as the master Spreadsheet and the name of the sheet will be the same as on the master page.
I found this code on another post that was for a similar problem
function onEdit(e) {
// Get the event object properties
var range = e.range;
var value = e.value;
//Get the cell position
var row = range.getRowIndex();
var column = range.getColumnIndex();
exportValue(row,column,value)
}
function exportValue(row,column,value) {
var ss = SpreadsheetApp.openById(targetID);
var s = ss.getSheetByName(targetSheetName);
var target = s.getRange(row, column);
target.setValue(value);
}
in this I understand what everything is doing except the ("var range = e.range; var value = e.value;") lines, is ths what im looking for or not, idk
Thanks in advance
:)
I have a bunch of data I want to put in to multiple sheets, and to do it manually would take time and I would like to learn scripting too.
So say I have a sheet with the states in one column.
I would like to have a script make new sheets based off the values of that column, and make a hyperlink to those sheets, and sort the sheets alphabetically.
In each sheet, I need to have the A1 cell the same name as the sheet.
Here is an example of states
Any suggestions would be helpful
Edit:
This is code that can make sheets based on the values of the columns.
function makeTabs() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var last = sheet.getLastRow();//identifies the last active row on the sheet
//loop through the code until each row creates a tab.
for(var i=0; i<last; i++){
var tabName = sheet.getRange(i+2,1).getValue();//get the range in column A and get the value.
var create = ss.insertSheet(tabName);//create a new sheet with the value
}
}
(note the "sheet.getRange(i+2,1" assumes a header, so pulls from the first column, starting on the second row)
I still need to:
Add a hyper link in the index sheet to the State's sheet: example: A2 on the Index sheet
would be =HYPERLINK("#gid=738389498","Alabama")
Also I need the A1 cell of the State's page to have the same info as
the index. example: Alabama's A1 cell would be =Index!A2
You could take a look at this script:
function createSheets(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var indexSheet = ss.getSheetByName('Index');
var indexSheetRange = indexSheet.getDataRange();
var values = indexSheetRange.getValues();
var templateSheet = ss.getSheetByName('TEMPLATE_the_state');
templateSheet.activate();
var sheetIds = [],
state,
sheetId,
links = [];
for (var i = 1 ; i < values.length ; i++){
state = values[i][0];
sheetId = undefined;
try{
var sheet = ss.insertSheet(state, {template: templateSheet});
SpreadsheetApp.flush();
sheet.getRange("A1:B1").setValues([['=hyperlink("#gid=0&range=A' +(i+1)+'","go back to index")',state]]);
sheetId = sheet.getSheetId();
}
catch (e) { Logger.log('Sheet %s already exists ' , sheet)}
sheetIds.push([sheetId,state]);
}
sheetIds.forEach(function(x){
links.push(['=HYPERLINK("#gid='+x[0]+'&range=A1","'+x[1]+'")']);
});
indexSheet.getRange(2,1,links.length,links[0].length).setValues(links) // in this case it is clear to us from the outset that links[0].length is 1, so we could have written 1
}
Note that in my version, I created a template sheet from which to base all the state sheets from. This wasn't what you asked for, but I wanted to see what it would do.
The resulting sheet is here: https://docs.google.com/spreadsheets/d/1Rk00eXPzkfov5e3D3AKOVQA2UdvE5b8roG3-WeI4znE/edit?usp=sharing
Indeed, I was surprised at how long it took to create the full sheet with all the states - more than 250 secs. I looked at the execution log, which I have added to the sheet in its own tab. There it is plain to see that the code is quick, but sometimes (why only sometimes, I don't know) adding a new tab to the spreadsheet and/or flushing the formulas on the spreadsheet is very slow. I don't know how to speed it up. Any suggestions welcome. (I could try the Google Sheets API v4, probably would be much faster ... but that is much more work and tougher to do.)
I'm a teacher, and I frequently need to copy blank grading rubrics, one copy per student in my class. The rubric is a Google Sheet. I cobbled together a script that will (1) access another sheet that contains the class roster, (2) read the students' names off the roster, and (3) create a new spreadsheet for each student and save it with the student's name as the file name. All of that works (it's super slow for some reason, but it works).
Now I'm trying to write the student's name to a cell on that student's copy of the rubric. My idea was to write the student's name to the relevant cell on the original rubric, then save a copy of that under the student's name. But that part doesn't work; the name in the cell does not match the file name. Instead, the name in the cell matches the prior student's name. Here's the code:
function onerubricperstudent(){
//"roster" is the roster spreadsheet. Change the value in quotation marks to whatever your roster's ID is.
var roster = SpreadsheetApp.openById("1SN2x6bKzga6bRwwvt5diuaETBiXeHqY7bLJMY5If9js");
//"sheet" is sheet to be copied
var sheet = SpreadsheetApp.getActiveSpreadsheet();
//range is the range on the roster sheet containing the student names
var range = roster.getRange('Sheet1!A1:A17');
//do this as many times as there are students in the class
for (var i = 1; i < 18; i++) {
//get the next student name
var studentname = range.getCell(i, 1);
//log the name (for troubleshooting if the script fails)
Logger.log(studentname.getValue());
//Write the student's name to the name cell on the sheet
sheet.getRange('B2').setValue(studentname.getValue());
//Make a copy of the sheet and save it with the student's name
DriveApp.getFileById(sheet.getId()).makeCopy(studentname.getValue());
}
}
The line that does not work as expected is:
sheet.getRange('B2').setValue(studentname.getValue());
What am I doing wrong?
Note: As a workaround, I added this OnOpen script, which copies the sheet name to the student-name cell when I open the rubric to grade the student's work:
function onOpen() {
var sheetname = SpreadsheetApp.getActive().getName();
var sheet = SpreadsheetApp.getActiveSpreadsheet();
sheet.getRange('B2').setValue(sheetname);
}
This gets the job done, but I'd still like to know what's wrong with the original code.
Thanks!
Your script does successfully set the value of cell B2 but the copy of the spreadsheet does not include the pending changes. In order for pending changes to be copied within the for loop, it appears that you must call SpreadsheetApp.flush(). This will apply all pending Spreadsheet changes (see docs on flush()).
Here is some code:
function onerubricperstudent(){
var roster = SpreadsheetApp.openById("YOUR-ROSTER-SHEET-ID-HERE");
var rubricSheet = SpreadsheetApp.getActiveSpreadsheet();
var rubricFile = DriveApp.getFileById(rubricSheet.getId());
// replace the worksheet name and desired range with your name/range below
var range = roster.getRange('Roster Master!A2:A21');
var studentNames = range.getValues();
for (var i = 0; i < studentNames.length; i++) {
rubricSheet.getRange('B2').setValue(studentNames[i]);
// SpreadsheetApp.flush() "forcefully" applies all pending Spreadsheet changes.
SpreadsheetApp.flush();
rubricFile.makeCopy(studentNames[i]);
}
}
You also note that creating copies with DriveApp seems slow. That is also my experience. Unfortunately, I don't think this can be optimized (if someone has tips - it would be great to see them). There is another question on this here: Google Apps Script : copying spreadsheet is very slow (but the answer isn't super helpful).
Here is an option: If you don't need individual spreadsheet files, you might want to consider making new sheets within the same spreadsheet. This would be significantly faster.
Here is some code:
function onerubricperstudent(){
var roster = SpreadsheetApp.openById("YOUR-ROSTER-SHEET-ID-HERE");
var rubricSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var rubricFile = DriveApp.getFileById(rubricSpreadSheet.getId());
// replace the sheet name with the name of the sheet you want to use as a template
var templateSheet = rubricSpreadSheet.getSheetByName("Rubric Master");
var range = roster.getRange('Roster Master!A2:A4');
var studentNames = range.getValues();
for (var i = 0; i < studentNames.length; i++) {
var newSheet = rubricSpreadSheet.insertSheet(studentNames[i], i+1, {template: templateSheet})
newSheet.getRange('B2').setValue(studentNames[i]);
}
}
I'm collecting data with a Google Form, and storing it in a spreadsheet.
I would like to write a script to create separate spreadsheet, sorted by name.
E.g.
I have three users: Daniel, Gilles and Jean Pierre.
I want to create a separate sheet from the main one, listing only the data submitted.
So, if the name is Daniel in row 2, I want to copy all the data in the row to the second sheet
So far:
function tri()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getDataRange().getValues();
var sheet2 = ss.getSheets()[1];
for (var t=1; t<data.length; t++)
{
if (data ='Daniel')
{
sheet2.appendRow([data]);
}
}
}
No need for code, you can do this in the spreadsheet. The solution I'd prefer would be to create named tabs for each of your users, put their name in cell A1 of their sheet, then use the spreadsheet QUERY function to populate their sheet. Something like this in cell A3, say:
=query('Form Responses'!A1:Z,"select * where B = '" &A1 & "'")
Adjust the source to match your reality ('Form Responses'!A1:Z).
But if you must use script, try this:
function tri()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Form Responses");
var data = sheet.getDataRange().getValues();
var users = ['Daniel', 'Gilles', 'Jean Pierre'];
for (var user=0; user<users.length; user++) {
// Open sheet with user's name; create if needed
var dest = ss.getSheetByName(users[user]);
if (!dest) dest = ss.insertSheet(users[user], user+1);
var newData = [];
newData.push(data[0]); // copy headers
for (var row=1; row < data.length; row++) {
// If row is for this user, copy it
if (data[row][1] === users[user]) newData.push(data[row]);
}
// Clear user's sheet, then save collected data
dest.clearContents();
dest.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
}
As a complement to Mogsdad (excellent) answer I'd like to add a detail that might be important.
Since your users are filling a form you can't be sure about the way they will be entering their names, will Daniel write "Daniel" or "DANIEL" or even "daniel" if he is in a hurry ? and for "Jean Pierre" it could even be worse since normally there should be a hyphen between Jean and Pierre !!!
So I'd suggest to add some logic around the name detection or, other possible solution if you know exactly who will fill this form, use a list select in your form to choose the names from.
This latest solution would be the simplest one of course...
Otherwise you can simply use :
...data[row][1].toUpperCase().replace(/ /g,'') == users[user];// users should then be defined in UPPERCASE
for example to avoid any upper/lower case error and extra spaces...