I have this sheet in my Google sheets spreadsheet which looks like this - (this is a simpler representation of my actual data)
Now let's say I want to find the row number of where animal = dog - wrt above data I should get 4 in return - as in the column 1, the value "dog" is in the 4th row. I built this code in Apps Script but it keeps returning -1 and I don't understand why...
var values = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
Logger.log(values);
//above prints [[animal, owner], [cat, Max], [doggo, Sam], [dog, Jack], [cow, Mary], [rabbit, Jimmy]]
var index = values[0].indexOf("dog");
var responsePrint = index;
Logger.log(responsePrint); // -1 is printed
What should I do if I want to get the 1st column of my sheet in an array and search for a particular value in it? I'm trying to avoid using a loop to scan each and every element, as my data might get large - so if an inbuilt function can do this, it'd be great for me... Any idea is appreciated! Thanks :)
P.S. I'd like to say this might sound like a question which has been asked before, but trust me I've searched a lot, and I can't seem to find a suitable solution for me...
values is a 2D array, or an array of arrays. The first index of values is the row and the second index is the column so values[1][0] would be the second row first column.
So in your case you could do this.
let index = values.findIndex( row => row[0] === dog );
To get the row you have to add 1 to the index because index are zero based.
What findIndex does is it takes each element of values which is a "row" and then looks at the first value in the row array and compares to "dog"
Reference
Array.findIndex()
Arrow function
If you want to use indexOf you need to isolate the first column of your data and then use the indexOf method:
function myFunction(){
var values = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getDataRange().getValues();
var index = values.map(r=>r[0]).indexOf("dog") + 1;
console.log(index); //outputs 4
}
Summary:
I need to get a range of values from one sheet, then set them into the first empty row of the second sheet. If that row is full, then append to the next.
I can get the script to set values into their corresponding cells, but not append; and I've been able to append a single cell value into an empty cell, but not the entire range. What am I not comprehending?
The goal:
Basically I'm taking user input (lets say race data) and saving it to another sheet for referencing later. (possibly to average race times by weight and height or something)
Research: I'm a bit new to this, but I've also done a good bit of research, such as ben collins free introductory course and other questions from here (just to name a couple):
[Get Range] SpreadsheetApp: getRange and setValues
[Copy Range] How to copy row ranges in Google docs?
Code
Grab my data:
const data1 = sheet1.getRange("A2:F2").getValues(); //grab data
Sets the range where I want it, but doesn't append:
sheet2.getRange("A2:F2").setValues(data1) //gets range and sets the value
So I've tried:
function r () {sheet2.getRange(newRow,1,1,data1.length).setValues(data1)};
return (r);
and even added:
sheet2.appendRow(data1);
(newRow is essentially getLastRow)
The above gives me a row of set values, then appends this in the following row: [Ljava.lang.Object;#f2a6014
-which in my research I've found what it is, but I don't understand why it happens.
I know I'm overlooking something or arranging something incorrectly but I cant figure out what it is that I'm not understanding.
Using your first two example I wrote this script and it works:
function copydata() {
const ss=SpreadsheetApp.getActive();
const sheet1=ss.getSheetByName('Sheet1');
const sheet2=ss.getSheetByName('Sheet2');
const data1 = sheet1.getRange("A2:F2").getValues();
sheet2.getRange("A2:F2").setValues(data1);
}
And this works also assuming that you realize that data1 is only a single row but it's still a two dimensional array so you have to use data1[0] to extract the single dimensional array from the two dimensional array
function copydatatofrom() {
const ss=SpreadsheetApp.getActive();
const sheet1=ss.getSheetByName('Sheet1');
const sheet2=ss.getSheetByName('Sheet2');
const data1 = sheet1.getRange("A2:F2").getValues();
sheet2.getRange("A2:F2").setValues(data1);
sheet2.appendRow(data1[0]);
}
So, I'm making a code that copies certain data from our EOD worksheet, and copy/pasting the data onto another sheet, which acts as a summary.
I've got most of the code already working, but running into trouble with the getRange output. It just shows "Range" in the cell instead of my input, which should all be numbers.
function myFunction() {
var source = [];
var destSheet = SpreadsheetApp.getActive().getSheetByName('SnapshotSpreadsheet');
var destRange = destSheet.getRange(destSheet.getLastRow()+1,2);
source.push(sheet.getRange('B20'));
source.push(sheet.getRange('E20:F20'));
source.push(sheet.getRange('H20'));
source.push(sheet.getRange ('J20:I20'));
source.push(sheet.getRange ('M18'));
source.push(sheet.getRange ('K20'));
source.push(insertDate());
destSheet.getRange(2,1,1,7).setValues([source]);
I've included just the portion that is causing the issue. I defined source as an array, and stored values into the array, then just called for them to be output on the next available line. Everything seems to be lining up alright, just the values are all "Range".
You need to use getValue() (if single cell) or getValues() (if multiple cells) to get the content of those ranges.
Cfr https://developers.google.com/apps-script/reference/spreadsheet/range#getValue()
You'll need to do .getValues() for it to return the values of the cells
var values = sheet.getRange('E20:F20').getValues();
This returns a Two Dimensional array of values, so you'll have to work around that in your code. For example the line of code I just wrote would be an array like
[[Value at E20, Value at F20]]
so in order to access the Value at E20, you would call values[0][0] or for Value at F20, - values[0][1]
I currently have a code that can get the row number of a cell that contains a specific string. Here's an example of the code:
var ss = SpreadsheetApp.getActiveSheet();
var values = ss.getRange("B:B").getValues();
var i=j=firstrow=lastrow=0;
for(i=0;i<values.length;i++)
for(j=0;j<values[i].length;j++) {
if(values[i][j]==5100) firstrow=i+1;
else if(values[i][j]=='EOL') lastrow=i-2;
}
I was wondering if it's possible to do something like above, but for columns, that way my script will not fall apart if an user accidentally move a column.
So, what are doing is using .getRange("B:B") to define that you want all rows in column B. Then using getValues() to return all of those rows as a multidimensional array(obviously this will only have one column - so you probably don't need that other for loop).
So instead you can just use .getRange(row, column) (where row and column are integers greater than 1), this way you can go through the spreadsheet one item at a time using getValue(). So you could initially look through the first row to find the column index you are after, and then look down the rows to find the data you require.
Something like this might work for you:
var ss = SpreadsheetApp.getActiveSheet();
var valueColumn;
for(i=1;i<ss.getLastColumn();i++) {
if (ss.getRange(1,i).getValue() == "ColumnName") {
valueColumn = i;
break;
}
}
//At this point I assume that we have a value in valueColumn, if not this won't work.
var values = ss.getRange(2, valueColumn, ss.getLastRow()).getValues();
var i=firstrow=lastrow=0;
for(i=0;i<values.length;i++) {
if(values[i][0]==5100) firstrow=i+1;
else if(values[i][0]=='EOL') lastrow=i-2;
}
One thing to keep in mind is that arrays are 0 based where as getRange(row,column[,rows]) is 1 based.
My spreadsheet is only small, so speed impacts of doing one call and getting all data is minimal, but if you are actually using a large sheet you might find one method works faster than another.
I have a Spreadsheet, like excel on Google Docs. I am using both Mozilla Firefox and Google Chrome, whichever works. Almost all my columns have dropdown list validation(you know, each cell has a dropdown list to select, I hope I made it clear). I arranged them when I first created the spreadsheet, gave all the columns validation from ranges I created.
My problem is, whenever I add a new row, that row doesn't have any validations, all of them are gone. The old rows still have the validations.
So then, I set the validations every time I add a new row, one by one. This is frustrating. Some people also had the same problem, asked online, but no one answered.
When I copy an empty row with validations and paste it on the new row, it works fine. So, what I am saying is, can you help me write a script for it? Like copying 5 rows when I execute the script?
I am trying to study the scripts but I did nothing nothing so far. I think
var actSc = SpreadsheetApp.getActiveSpreadsheet();
var range = actSc.getRange("A1:B1");
This all I got from the examples I saw. I mean it. I got nothing.
If this copies the ranges of one cell, then I guess I should do it for all my columns.
But how do I put them in the new row? Is there something like setRange?
I could really use some help. This is driving me crazy and I really don't get this script thing.
What I mean by range is that I have ranges like "STATES" and it includes "NY,LA,CA" etc. This NY,LA,CA fills the dropdown list in the cells of that STATES column. I hope this getRange means this range.
Sorry about my English.
If I understand correctly, you want to script a function that will add new rows to a sheet and maintain the existing validations for your columns. This is certainly possible and not too difficult. One approach could be a "refresh validations" function that updates your entire sheet all at once, in the event that you want to reuse it in other sheets. First, though, it sounds like you could use a brief overview of the object classes you need to know about to do basic Google Apps Scripts:
SpreadsheetApp - Think of this class as the foundation of the Spreadsheet Service. It provides file I/O and functionality that is not tied to specific spreadsheets, per se, such as UI and the creation of Data Validation sets. It's the interface to all of your individual spreadsheet documents.
Spreadsheet - A spreadsheet document file, which can contain multiple Sheets. This is what gets created when you create a new Google Sheets document in Drive. Provides document-level functions, such as the ability to manage ownership, set permissions, access metadata, etc. There's some overlap with the Sheet class, so this one can seem like a bit of a mishmash.
Sheet - An individual sheet is what you normally think of as a spreadsheet: a set of rows and columns. Each Spreadsheet document can contain many, distinct Sheets. The Sheet class lets you modify the overall appearance of the sheet. You can freeze or hide rows, protect ranges of cells from being edited, add/delete rows and columns, etc. You can also get data about the sheet, such as the last row that has content or the maximum range of the whole sheet.
Range - Dropping down another level, we reach the Range object, which represents a certain rectangular area of cells. This can be as small as a single cell or as large as the whole sheet. It does not seem possible, however, for Ranges to represent discontiguous cells. This is where you had some trouble, because you treated the Range object as content that you could copy and paste in your sheet, which is understandable. But a Range isn't the data in the cells it represents. It's just an interface to those cells. If you want to access the data itself, you have to drop down to the bottom level of the hierarchy:
Value - The actual contents of your sheets are normal JavaScript values: strings, integers, Booleans, etc. that you can manipulate with the subset of JavaScript that Google Apps Script supports.
In order to do something with the values in your sheet, you first get the Range object from the Sheet (which you get from the SpreadsheetApp) and then get the values from the Range:
var values = SpreadsheetApp.getActiveSheet().getRange("A1:B1").getValues(); // returns [[]]
Note that getValues() returns a multi-dimensional array. As a representation of the values in your sheet, it looks like this:
// row 1 [[column A, column B, column C, column D, ...],
// row 2 [column A, column B, column C, column D, ...],
// row 3 [column A, column B, column C, column D, ...],
// row 4 [column A, column B, column C, column D, ...],
// row 5 [column A, column B, column C, column D, ...], ...]
So if the range A1:B1 is a range of one row and two columns, you can retrieve the values with A1 notation or by specifying the upper left row and column of the range, and the number of rows and number of columns you want to retrieve:
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("A1:B1");
var range = sheet.getRange(1, 1, 1, 2); // row 1, column 1, 1 row, 2 columns
var values = range.getValues(); // returns [[50, 100]]
If the value in A1 is 50, and the value in B1 is 100, the last function above will return [[50, 100]]. You can access individual cell values directly, too:
var range = sheet.getRange("A1");
var value = range.getValue(); // returns 50
var cell = range.getCell().getValues(); // returns [[50]]
Obviously, you can set the values of ranges, too:
var range = sheet.getRange("A1:B2");
range.setValues([[50, 100]]);
range = sheet.getRange(1, 1); // same as sheet.getCell(1, 1)
range.setValue(50); // the value of A1, or row 1 column 1, is now 50
The next step is to figure out how the Data Validation class works. You create a Data Validation object using the Data Validation Builder, which lets you chain together a series of rules to apply to a range. You then set the range to that Data Validation rule set:
var stateList = ["AK", "AL", "AR", ...];
var rules = SpreadsheetApp.newDataValidation() // create a new Data Validation Builder object and use method chaining to add rules to it
.requireValueInList(stateList, true) // first param is the list of values to require, second is true if you want to display a drop down menu, false otherwise
.setAllowInvalid(false) // true if other values are allowed, false otherwise
.setHelpText("Enter a state") // help text when user hovers over the cell
.build();
range.setDataValidation(rules); // apply the rules to a range
Now you can insert rows and the rules should copy over into them automatically:
var lastRow = sheet.getLastRow(); // get the last row that contains any content
sheet.insertRowAfter(lastRow);
Or copy the rules and use them elsewhere:
var cell = sheet.getRange(1, 1, 1, 1);
var rule = sheet.getDataValidation(); // returns rule
var range = sheet.getRange("A1:B1");
var rules = range.getDataValidations(); // returns [[rules, rules]]
var lastRow = sheet.getLastRow(); // or sheet.getMaxRows()
range.setDataValidations(rules);
So you can very easily put these concepts together to write whatever sort of function you need to add rows, build validation rule sets, and add validations to new ranges of cells. You can do most of these things more concisely than I have here, but it sounds like you're looking for a more in-depth explanation. I hope it helps.
var sheetToUpdate = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheetToUpdate.insertRowAfter(sheetToUpdate.getLastRow());
var rangeToUpdate = sheetToUpdate.getRange(sheetToUpdate.getLastRow()+1,1,1,sheetToUpdate.getMaxColumns());
sheetToUpdate.getRange(sheetToUpdate.getLastRow(),1,1,sheetToUpdate.getMaxColumns()).copyTo(rangeToUpdate, {formatOnly:true});