I am using Google app scrips and I want to iterate through a spreadsheet that will be updated weekly. (this is why i dont want to set a range i want to be able to iterate through the entire sheet.)
Is this possible? If yes can you give an example of how this would be done?
and if this isn't a good idea, why not?
Thank you!
Example code
function doGet(e){
var ss = SpreadsheetApp.openById('key in here');
var sheet = ss.getSheetByName("Form Responses");
var range = sheet.getRange(1,1);
var dataRange = range.getValue().toString();
app.add(app.createHTML("There are " + dataRange + " posts today"))
return app;
Something like this, but I want to be able to see the whole sheet not just the range
Henrique Abreu and Srik provided you with correct answer - getDataRange on sheet should serve your purpose.
function doGet(e){
var sheet = SpreadsheetApp.openById('spreadsheetId').getSheetByName('sheetName');
var data = sheet.getDataRange().getValues();;
...
}
data is now 2-dimensional array, you can iterate through it, get last column/row containing content etc. Please read through class reference here: https://developers.google.com/apps-script/reference/spreadsheet/sheet
You cannot iterate over the sheet by itself, but always iterate over the vales of range.
However you don't have to use a fixed range but can compute the range at every script execution.
To do this you could use getlastcolumn() and getLastRow().
This two methods return the last column or row with content in it.
A commodity method is getDataRange() which directly gives you the range with data in it.
Every script execution this range will extend over all your cells and columns with content.
Look at the example from Google API documentation:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This represents ALL the data
var range = sheet.getDataRange();
var values = range.getValues();
// This logs the spreadsheet in CSV format with a trailing comma
for (var i = 0; i < values.length; i++) {
var row = "";
for (var j = 0; j < values[i].length; j++) {
if (values[i][j]) {
row = row + values[i][j];
}
row = row + ",";
}
Logger.log(row);
}
Hope that helps.
Related
I have a range of cells in Google Sheets, some of them have notes attached.
If there's a note attached to a cell, I need to put the note in a separate cell, and put the location of that note in another cell.
I found this script elsewhere:
function getNote(cell)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange(cell)
return range.getNote();
}
but when I try to use it I get an error "Exception: Range not found (line 12)."
But this script only gets me halfway there as it only gets the note and puts it in a cell. I also need to know what cell the note came from.
Any help is greatly appreciated.
In the script above the function getNote() expects the paramter cell
If you just run the script without calling getNote() from another function / an environment where it gets a values for cell assigned, the script will fail wiht the error you obtained.
Indeed, this script doe snot not meet your needs. What you probably want is to screen all your cells for the one that have notes.
What you need to decide is into which cells you want to put the note and the cell notation.
Below is a sample that you need to adapt for your needs:
function getNotes() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
//if you have only one sheet in the spreadsheet, otherwise use ss.getSheetByName(name);
var sheet = ss.getActiveSheet();
var range = sheet.getDataRange();
var results = range.getNotes();
for (var i = 0; i < results.length; i++) {
for (var j = 0; j < results[0].length; j++) {
//if a not empty note was found:
if(results[i][j]){
var note = results[i][j];
var cell = range.getCell(i+1, j+1);
var notation = cell.getA1Notation();
//adjust the offset as function of the column / row where you want to output the results
cell.offset(0, 1).setValue(note);
cell.offset(0, 2).setValue(notation);
}
}
}
}
Important references:
getNotes()
getA1Notation()
getDataRange()
getCell(row, column)
offset(rowOffset, columnOffset)
I have a problem where I have two sheets. one sheet is the source spreadsheet and another is a target spreadsheet. The source spreadsheet has a source sheet has which is the master database and the target spreadsheet has the target where we want to fetch data from source sheet based on emails provided in the Emails tab in the target spreadsheet.
I want the following things to happen with a script and not with IMPORTRANGE or QUERY:
The target spreadsheet will have multiple copies so I want to connect the target spreadsheet with the source spreadsheet based on the source spreadsheet's id.
I want the email matches to be case insensitive so that the users of the target spreadsheet can type emails in any case.
The Emails can go up to 50 or let's say get the last row for that column.
It will be great if the script shows a pop up saying updated after it has fetched the data.
The source sheet might have data up to 15000 rows so I am thinking about speed too.
I have shared both of the spreadsheets with hyperlinks to their names. I am not really great at scripts so it will be helpful if you can leave comments in it wherever you feel like. I would truly appreciate your help.
Thanks in advance!
Script here:
function fetch() {
//get the sheets
var source_Ssheet = SpreadsheetApp.openById('19FkL3rsh5sxdujb6x00BUPvXEEhiXfAeURTeQi3YWzo');
var target_Ssheet = SpreadsheetApp.getActiveSpreadsheet();
//get the tabs
var email_sheet = target_Ssheet.getSheetByName("Emails");
var target_sheet = target_Ssheet.getSheetByName("Target Sheet");
var source_sheet = source_Ssheet.getSheetByName("Source Sheet");
//get ranges
var email_list = email_sheet.getRange("B2:B");
var target_sheet_range = target_sheet.getRange("A1:F100");
var source_sheet_range = source_sheet.getRange("A1:F100");
//get last rows
var last_email_name = email_list.getLastRow();
var last_target_sheet_range = target_sheet_range.getLastRow();
var last_source_sheet_range = source_sheet_range.getLastRow();
//start searching for emails
for (var i=3; i < last_email_name.length+1; i++)
{
for(varj=3; j< last_source_sheet_range.length+1; j++ )
{
if(source_sheet_range[j][3].getValue() == email_list[i][3].getValue())
{
//copy matches to target sheet
target_sheet.getRange((last_target_sheet_range + 1),1,1,10).setValues(master_sheet_range[j].getValues());
}
}
}
}
Several things
last_email_name and last_source_sheet_range are numbers - they do not have any length, this is why your first forloops are not working
You are missing a space in varj=3;
email_list[i][3].getValue() does not exist because email_list only includes B - that only one column. I assume you meant email_list[i][0].getValue()
ranges cannot be addressed with the indices [][], you need to retrieve the values first to have a 2D value range.
You email values in the different sheets do not follow the same case. Apps Script is case sensitive, to suee the == comparison you need to use the toLowerCase() method.
Also mind that defining getRange("B2:B") will include many empty rows that you don't need and will make your code very slow. Replace it through getRange("B2:B" + email_sheet.getLastRow());
Have a look here at the debugged code - keep in mind that there is still much room for improvement.
function fetch() {
//get the sheets
var source_Ssheet = SpreadsheetApp.openById('19FkL3rsh5sxdujb6x00BUPvXEEhiXfAeURTeQi3YWzo');
var target_Ssheet = SpreadsheetApp.getActiveSpreadsheet();
//get the tabs
var email_sheet = target_Ssheet.getSheetByName("Emails");
var target_sheet = target_Ssheet.getSheetByName("Target Sheet");
var source_sheet = source_Ssheet.getSheetByName("Source Sheet");
//get ranges
var email_list = email_sheet.getRange("B2:B" + email_sheet.getLastRow()).getValues();
var target_sheet_range = target_sheet.getRange("A1:F100").getValues();
var source_sheet_range = source_sheet.getRange("A1:F100").getValues();
var last_target_sheet_range = target_sheet.getLastRow();
//start searching for emails
for (var i=1; i < email_list.length; i++)
{
for(var j=1; j< source_sheet_range.length; j++ )
{
if(source_sheet_range[j][0].toLowerCase() == email_list[i][0].toLowerCase())
{
target_sheet.getRange((last_target_sheet_range + 1),1,1,6).setValues([source_sheet_range[j]]);
}
}
}
}
Background: My coworkers originally each had a worksheet within the same Google Sheets file that makes a lot of calculations (and was getting unusable). Now, everyone has their own (known) Google Sheets file. To run the same calculations, we need to consolidate all that data into a master sheet (image ref below). We tried =importrange(...), but it's too heavy and breaks often (i.e., Loading... and other unfilled cells).
I've written some code to do this import, but right now its only manual: manually repeating the code and manually add the sheet IDs and changing the destrange.getRange(Cell range) each time. We have 80+ analysts, and fairly high turnover rates, so this would take an absurd amount of time. I'm new to Sheets and Apps Script, and know how to make the script use a cell as reference for a valid range or a valid ID, but I need something that can move a cell down and reference the new info.
Example:
Sheet 1 has a column of everyone Sheet ID
Script Pseudocode
get first row's id(Row 1), get sheet tab, get range, copies to active sheet's corresponding row(Row 1).
gets second row's id(Row 2), get sheet tab, get range, copies to active sheet's corresponding row (Row 2)
etc.
My script understanding is way to low to know how to process this. I have no idea what to read and learn to make it work properly.
function getdata() {
var confirm = Browser.msgBox('Preparing to draw data','Draw the data like your french girls?', Browser.Buttons.YES_NO);
if(confirm == 'yes'){
// I eventually want this to draw the ID from Column A:A, not hard-coded
var sourcess = SpreadsheetApp.openById('1B9sA5J-Jx0kBLuzP5vZ3LZcSw4CN9sS6A_mSbR9b26g');
var sourcesheet = sourcess.getSheetByName('Data Draw'); // source sheet name
var sourcerange = sourcesheet.getRange('E4:DU4'); // range
var sourcevalues = sourcerange.getValues();
var ss = SpreadsheetApp.getActiveSpreadsheet(); //
var destsheet = ss.getSheetByName('Master Totals'); //
// This range needs to somehow move one down after each time it pastes a row in.
var destrange = destsheet.getRange('E4:DU4');
destrange.setValues(sourcevalues); // Data into destsheet
}
}
Any suggestions are greatly appreciated!
Thanks to tehhowch for pointing me in the right direction!
function getdata() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var destsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Master Totals');
var confirm = Browser.msgBox('Drawing Data','Would you like to update the sheet? It may take 2 to 5 minutes.', Browser.Buttons.YES_NO);
if(confirm =='yes'){
var lr = ss.getLastRow();
for (var i = 4; i<=lr; i++) {
var currentID = ss.getRange(i, 1).getValue();
var sourcess = SpreadsheetApp.openByUrl(currentID);
var sourcesheet = sourcess.getSheetByName('Data Draw');
var sourcerange = sourcesheet.getRange('E4:DU4');
var sourcevalues = sourcerange.getValues();
var destrange = destsheet.getRange('E' +i+':'+ 'DU'+ i);
destrange.setValues(sourcevalues);
I just had to learn how to use a variable loop.
Edit: thanks also to Phil for making my question more presentable!
Now that you've figured out one way to do it, I'll offer an alternative that uses batch methods (i.e. is much more time- and resource-efficient):
function getData() {
var wb = SpreadsheetApp.getActive();
var ss = wb.getActiveSheet();
var dest = wb.getSheetByName('Master Totals');
if (!dest || "yes" !== Browser.msgBox('Drawing Data', 'Would you like to update the sheet? It may take 2 to 5 minutes.', Browser.Buttons.YES_NO))
return;
// Batch-read the first column into an array of arrays of values.
var ssids = ss.getSheetValues(4, 1, ss.getLastRow() - 4, 1);
var output = [];
for (var row = 0; row < ssids.length; ++row) {
var targetID = ssids[row][0];
// Open the remote sheet (consider using try-catch
// and adding error handling).
var remote = SpreadsheetApp.openById(targetID);
var source = remote.getSheetByName("Data Draw");
var toImport = source.getRange("E4:DU4").getValues();
// Add this 2D array to the end of our 2D output.
output = [].concat(output, toImport);
}
// Write collected data, if any, anchored from E4.
if(output.length > 0 && output[0].length > 0)
dest.getRange(4, 5, output.length, output[0].length).setValues(output);
}
Each call to getRange and setValues adds measurable time to the execution time - i.e. on the order of hundreds of milliseconds. Minimizing use of the Google interface classes and sticking to JavaScript wherever possible will dramatically improve your scripts' responsiveness.
I have been searching for a way to copy certain cells from a row and paste them into another spreadsheet, but all I can seem to find are ways to do that just from sheet to sheet within one spreadsheet or questions that deal with code way above my head. I'm just now learning to code in Google Spreadsheets and I can't seem to get it right. Here is my code for now, I'm working on just copying one cell first and after I can do that I'll get a loop to iterate through the row and pick the cells I want to copy.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var master = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c');
var target = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c');
var master_sheet = master.getSheetByName("Steve2");
var target_sheet = target.getSheetByName("Corbin1");
var master_range = master_sheet.getRange("A1");
var target_range = target_sheet.getRange("A1");
master_range.copyTo(target_range);
Right now it is giving me an error saying that it cannot call the getRange method of null. I'm not sure if I'm using OpenById correctly or if I can even use that in this situation.
OK I've got it working now. It copies the row perfectly and it copies only the cells I want. Now I need help with the pasting part. It copies everything fine and puts it into the other sheet great, but I need it to copy into the next available row and into the first available columns. So if row 5 is the last column of data, I need it to paste into row 6 and take up the first 6 or so columns.
This is what I have so far.
function menuItem1() {
var sss = SpreadsheetApp.openById('0AgcCWQn-aoI1dFpLVE4tSENwcThrYnlMUzhuRmdWU2c'); // sss = source spreadsheet Steve2
var ss = sss.getSheetByName('Sheet1'); // ss = source sheet
//Message box asking user to specify the row to be copied
var answer = Browser.inputBox('What row would you like to copy?');
var range = parseInt(answer);
var array = [1,2,3,9,12,30];
//Runs a loop to iterate through array, using array elements as column numbers
for(var i = 0; i < array.length; i++){
var SRange = ss.getRange(answer,1,1,array[i]);
//get A1 notation identifying the range
var A1Range = SRange.getA1Notation();
//get the data values in range
var SData = SRange.getValues();
}
var tss = SpreadsheetApp.openById('0AgcCWQn-aoI1dF96X2dBT2dVVFZ2SU1NRWdYTDJhT2c'); // tss = target spreadsheet Corbin1
var ts = tss.getSheetByName('Sheet1'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange(A1Range).setValues(SData);
//Confirmation message that the row was copied
Browser.msgBox('You have successfully copied Row: ' + answer);
}
You are getting this error maybe because your spreadsheet does not have a sheet called Steve2 or Cobin1. Try using the method master.getSheets()[0], this way you will get the first sheet without using their name.
You can algo use this piece of code to check the sheets names:
for(var x in master.getSheets()) {
Logger.log(master.getSheets()[x].getSheetName());
}
best,
I am working on adding functionality to a Google Spreadsheet. The spreadsheet imports data from the web, and I have it all formatted nicely. One of my columns is a series of strings, formatted in one of two ways - String or *String * without the space (basically importing italics from the web).
I am trying to come up with a script that runs when I open my spreadsheet, that will:
Unhide all rows in my spreadsheet
Loop through the spreadsheet
Hide every row where column 2(B) begins with an Asterisk
I have the following:
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("DoDH");
sheet.showRows(1, sheet.getMaxRows());
for(var i=1; i<sheet.getMaxRows()+1; ++i){
if (sheet.getRange(i, 2).getValue().){
sheet.hideRow(i)
}
}
}
I don't know how to access the string inside each cell, and how to access characters within the string. Thank you in advance for any help.
Here is updated code. See comments to have na insight
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("DoDH");
var maxRows = sheet.getMaxRows();
//show all the rows
sheet.showRows(1, maxRows);
//get data from clumn B
var data = sheet.getRange('B:B').getValues();
//iterate over all rows
for(var i=0; i< data.length; i++){
//compare first character, if asterisk, then hide row
if(data[i][0].charAt(0) == '*'){
sheet.hideRows(i+1);
}
}
}