I'm learning Google script as I go along and came across an issue that I could not find a solution for.
I have a function that takes in several several strings and one cell as params.
I assume passing a cell is not same as passing its value (string too btw)
Please find attached code:
//return id assigned to data(cell) sheetname
function findInColumn(column, data, colName, sheetname) {
/*
data = cell (cell value is 'bag_backpack.png') does not work
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
var range2 = SpreadsheetApp.getActiveSheet().getRange(row,col+1);
data = range2.getValue(); (cell value is 'bag_backpack.png') <---fail too
data = 'bag_backpack.png'; <---works
*/
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetname);
var column = sheet.getRange(column + ":" + column); // like A:A
var values = [];
for (var index = 0; index < column.getValues().length; index++) {
values.push(column.getValues()[index][0])
}
var colIndex = getByName(colName, sheetname);
var rowIndex = values.indexOf(data);
//grab id value of data
var range = sheet.getRange(rowIndex+1,colIndex+1);
var data = range.getValue();
return data
}
While I value and need your feedback I kindly request your bear in mind I'm a novice at best and I've spend several hours searching before asking here.
Thank you for your help.
Edit: bag_backpack.png is the content of a cell I'm searching in a column to get the row number of said cell.
var rowIndex = values.indexOf(data);
Returns the index I need.
However... if I feed a cell to the function instead of a string like a cell elsewhere with bag_backpack.png as its content or even derive said value from it:
var range = SpreadsheetApp.getActiveRange();
var col = range.getColumn();
var row = range.getRow();
var range2 = SpreadsheetApp.getActiveSheet().getRange(row,col+1);
data = range2.getValue(); (cell value is 'bag_backpack.png') <---fail too
In said case:
var rowIndex = values.indexOf(data);
gives out -1 instead of index desired.
Most of what you have doesn't make sense to me. I'm guessing that this is what you want. Since I can't figure out what you want, perhaps you can tell me what I missed.
function findInColumn(column,sheetname) {
var sh=SpreadsheetApp.getActive().getSheetByName(sheetname);
var rg=sh.getRange(column + ":" + column); /
var vA=rg.getValues();
var values = [];
for (var i=0;i<vA.length; i++) {
values.push(vA[i][0]);
}
return values
}
I want to thank everyone for taking the time to reply.
the issue was NOT with the code but with some of the first filename having uppercase in the id,name sheet while the binder sheet it did not.(at least 5 hours on Tent.png/tent.png)
I'm attaching a link to my finished work in hopes it benefits anyone.
https://docs.google.com/spreadsheets/d/1jCy1I4r6PeY3kUWrhNno2XO18Jghq6_b1kyN3AflidM/edit?usp=sharing
Related
I have a Google Form attached to a spreadsheet. Everytime the data is submitted via the form into the spreadsheet. Then the spreadsheet should automatically send an email to several individuals but, it's not working.
Here is my code:
function myFunction(row) {
var sheets = SpreadsheetApp.getActiveSpreadsheet();
var sheet = sheets.getSheets()[0]; // Form Responses 1
var columnName = sheet.getRange("A1:S1").getValues();
var dataRange = sheet.getRange(row);
var data = dataRange.getValues();
var responseObj = {};
var carId = "";
for (var i = 2; i < columnName[0].length; i++) {
var key = columnName[0][i];
var value = dateFormat(data[0][i],key);
responseObj[key] = value;
if(key === "Car ID"){
carId = value;
}
}
var htmlBodyLoc = doGet(responseObj);
MailApp.sendEmail({
to: 'person.one#gmail.com,person.two#gmail.com,person.three#gmail.com',
subject:'Car Inspection - ' + outletId + ' ' + new Date(),
htmlBody: htmlBodyLoc,
});
}
I am actually getting an error on this line: var dataRange = sheet.getRange(row);
Thanks.
You have 4 ways to call sheet.getRange()
getRange(row, column)
It is for single cells ranges.
If you are from VBA, this is the most approximate to worksheet.Cells
getRange(row, column, numRows)
This way you can make a range of singles columns and multiple rows, useful sometimes
getRange(row, column, numRows, numColumns)
This is the way to go, programmatically.
E.g sheet.getRange(1,1,2,2) will get you the range A1:B2
And finally there is getRange(a1notation) which you can use like sheet.getRange("A1:B2")
If you are trying to get a single cell of data, maybe you can just change
var dataRange = sheet.getRange(row);
To
var dataRange = sheet.getRange(row, yourFixedColumn);
yourFixedColumn being an Integral with index 1 for the column E.g column A = 1
Otherwise you must change the passed argument row to something that complies with the methods listed above.
I am working on a google app script to fetch a range, multiply one column in the range by another column in the range, then output to a different column within the original range. This should be simple, but I can't figure it out.
function myFunction() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var data = sheet.getRange("A1:B22").getValues();
var newData = []
for (i in data){
var row = data[i];
var multiply = row[0] * row[1]
newData.push(multiply)
}
sheet.getRange(1,3,22,1).setValues(newData)
}
Thanks for the recommendation, but that didn't work unfortunately. The reason I'm not using the arrayformula function is because this is actually a small piece of a larger, more complicated function.
What did end up working is pushing the "multiply" variable into newData as an array by putting it in brackets.
function myFunction() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var data = sheet.getRange("A1:B22").getValues();
var newData = []
for (i in data){
var row = data[i];
var multiply = row[0] * row[1]
newData.push([multiply])
Logger.log(newData)
}
sheet.getRange(1,3,22,1).setValues(newData)
}
I'm trying to move a row of data from one sheet to another in the same spreadsheet based on a value of today's date.
In column "A", I have a date. I want to move the row if the date entered in column "A" is older than today's date. (it's a flight schedule for aircraft and I want to move flights that have already occured onto a sheet called "Past Flights".) The name of the active sheet is "Flight Schedule".
After the row is moved, I want it to delete off the "Flight Schedule" sheet. I know where to add scripts, but have no idea how to make this happen.
Here is what I have tried. I think on line "If (data.link >1..." data.link isn't the right one to use. But I can't find something for indicating older than todays date.
function approveRequests() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
if (sheetName == "Flight Shedule") {
var range = sheet.getActiveRange(),
startRow = range.getRowIndex(),
numRows = range.getNumRows(),
numCols = range.getNumColumns()
if (numCols == 9) {
if (data.length > 1) {
var values = range.getValues(),
nextSheet = ss.getSheetByName("Past Flight"),
lastRow = nextSheet.getLastRow();
nextSheet.getRange(lastRow+1,1,numRows,3).setValues(values);
sheet.deleteRows(startRow,numRows);
}
}
}
}
Any help would be huge!
Thanks!
Ok, I will go in with some general tips based on your current code first.
In your function you do a sheet = ss.getActiveSheet() which is redundant because you already have SpreadsheetApp.getActiveSpreadsheet().Also I would recommend to avoid this
var ss = SpreadsheetApp.getActiveSpreadsheet()
sheet = ss.getActiveSheet(),
sheetName = sheet.getName(),
data = sheet.getDataRange().getValues();
in favour of this:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var sheetName = sheet.getName();
var data = sheet.getDataRange().getValues();
which is much more easy to read and change without making mistakes.
data.length has nothing to do with current date, it will simply be the length of the array. So if you select 1 row of data, it will be 1, if you select 2 rows it will be 2 etc. .getValues() will return an array where data[row][col]. What you are looking for is getting the value of the flight time, converting it into a date object (not a google specific thing, just general javascript). Then use var now = new Date() and compare the two.
I would also recommend to re-think your if statements. There are a lot of better ways to grab the row data than selecting the row manually and then running the function. You can save a lot of lines of code should you decide to actually make this run automatically, because as it is, it will run only when called manually.
This sample is working:
function approveRequests() {
// Initialising
var ss = SpreadsheetApp.getActiveSpreadsheet();
var scheduleSheet = ss.getSheetByName("Flight Shedule");
var pastSheet = ss.getSheetByName("Past Flight");
var lastColumn = scheduleSheet.getLastColumn();
// Check all values from your "Flight Schedule" sheet
for(var i = scheduleSheet.getLastRow(); i > 0; i--){
// Check if the value is a valid date
var dateCell = scheduleSheet.getRange(i, 1).getValue();
if(isValidDate(dateCell)){
var today = new Date();
var test = new Date(dateCell);
// If the value is a valid date and is a past date, we remove it from the sheet to paste on the other sheet
if(test < today){
var rangeToMove = scheduleSheet.getRange(i, 1, 1, scheduleSheet.getLastColumn()).getValues();
pastSheet.getRange(pastSheet.getLastRow() + 1, 1, 1, scheduleSheet.getLastColumn()).setValues(rangeToMove);
scheduleSheet.deleteRow(i);
}
}
}
}
// Check is a valid date
function isValidDate(value) {
var dateWrapper = new Date(value);
return !isNaN(dateWrapper.getDate());
}
So yes, It's not the optimized solution (cause of the use of several sheet.getRange() method), but it's working and allowing to have a clear code.
I have two sheets.
First is data from JSON with max results 100 rows. It contains 8 columns.
Second is the data I add manually and then write to the first sheet based on matched title.
For example, if both titles match then create a new column "Category" in first sheet from second sheet. The second sheet contains 50 rows and 8 columns.
When I run this script it throws error: We're sorry, we were unable to process the operation because it contains too much data. I tried to remove line by line to figure out what is causing it. And it seems like when I remove this line:
data[i][11] = descr; // this is a paragraph long description text
It is working fine. Also, if I remove all the other data I want to write in, and run only data[i][11] = descr; it also chokes. So, it doesn' seem like there is too much data. Any ideas how to make it work? Workarounds?
Edit: here is a copy of the spreadsheet:
https://docs.google.com/spreadsheet/ccc?key=0AhVWrVLsk5a5dFRaeFQxZUc3WlZOR0h4N09pOGJBdGc&usp=sharing
Thanks!
function listClasses(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //list of all upcoming classes
var sheet1 = ss.getSheets()[1]; //list of titles
var data = sheet.getDataRange().getValues(); // read all data in the sheet
var data1 = sheet1.getDataRange().getValues();
for(n=1;n<data1.length;n++){
var title1 = data1[n][0];
var category = data1[n][1];
var image_url = data1[n][2];
var available = data1[n][3];
var descr = data1[n][4];
var prerequisites = data1[n][5];
var mAccess = data1[n][6];
var notes = data1[n][7];
// compare Check if title appears in column B of sheet 1.
if (ArrayLib.find(data1, 0, title1) != -1) {
// Yes it does, do something in sheet 0
for( var i = data.length -1; i >= 0; --i )
if (data[i][1] == title1)
{
//Logger.log(descr);
if (data[i].length < 14){
data[i].push(' ');
}
data[i][8] = category;
data[i][9] = image_url;
data[i][10] = available;
data[i][11] = descr;
data[i][12] = prerequisites;
data[i][13] = mAccess;
data[i][14] = notes;
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}
}
}
I had a look at your code, but I could not make it work.
I too get such error messages, but so far have encountered them when I am processing a few thousand rows (with only 4 columns) but each row containing as much text or more than your description.
I only know how to use a simple way, which I tried for your case too. The following code I think does what you need:
function listClasses2(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; //list of all upcoming classes
var sheet1 = ss.getSheets()[1]; //list of titles
var data = sheet.getDataRange().getValues(); // read all data in the sheet
var data1 = sheet1.getDataRange().getValues();
var newDataArray = [data[0]];
for(var n=1; n < data.length ; n++){
for(var j=0; j< data1.length ; j++){
if(data[n][1] == data1[j][0]){
newDataArray.push([data[n][0] ,data[n][1] ,data[n][2] ,data[n][3] ,data[n][4] ,data[n][5] ,data[n][6] ,data[n][7] ,data1[j][1] , data1[j][2] , data1[j][3] , data1[j][4] , data1[j][5] , data1[j][6], data1[j][7] ]) ;
break;}
}
newDataArray.push(data[n])
}
sheet.getRange(1, 1, newDataArray.length, newDataArray[0].length).setValues(newDataArray);
}
(I have just noticed that my var n is not the same as your var n ... sorry for the possible confusion)
I'm writing an app that will import columns from one sheet to another. The .getLastRow method will only apply to the whole sheet, but can't be used to get last row of a column. There is an issue open requesting this feature.
I've written something with the help of the 2D Array library from the folks over at Google Script Examples: https://sites.google.com/site/scriptsexamples/custom-methods/2d-arrays-library
I've gotten a working version that finds the last row in a specific column, but I suspect it's rather ineffecient.
function readRows() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var numRows = sheet.getLastRow();
var numColumns = sheet.getLastColumn();
var data = sheet.getRange(1, 1, numRows, numColumns).getValues();
//Get the Headers, Search for a value of the headers and index
var headerArray = sheet.getRange(1, 1, 1, numColumns).getValues();
var flip = ArrayLib.transpose(headerArray)
var search = "Greens";
var whereGreen = ArrayLib.indexOf(flip, 0, search);
//Get the value of the column with matching headers, and looks up Column length.
var values = sheet.getRange(1, whereGreen +1, numRows, 1).getValues();
//finds last value, makes string
for(; values[numRows - 1] == "" && numRows > 0; numRows--) {}
var lastValue = values[numRows - 1].toString();
//Indexes where the string is, which gives the value -1 of the last row in column.
var lastRowCol = ArrayLib.indexOf(values, 0, lastValue);
Logger.log(lastRowCol +1);
}
Can anyone help me get to a streamlined version? I'm sure JavaScript could do it, but I'm rather light on my knowledge in that department.
The code can be made more efficient by reducing the number of calls to the spreadsheet service. The following code is much faster:
function readRows() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getDataRange().getValues();
var numRows = data.length;
//Get the Headers, Search for a value of the headers and index
var headerRow = data[0];
var search = "Greens";
var whereGreen = headerRow.indexOf(search);
//finds last value, makes string
while( data[numRows - 1][whereGreen] == "" && numRows > 0 ) {
numRows--;
}
var lastValue = data[numRows - 1][whereGreen].toString();
Logger.log( 'Last row: '+ numRows );
Logger.log( 'Last value: '+ lastValue );
// Not clear what this does, what more information is needed?
//Indexes where the string is, which gives the value -1 of the last row in column.
//var lastRowCol = ArrayLib.indexOf(values, 0, lastValue);
// Logger.log(lastRowCol +1);
}
I replaced the for loop with a while loop, but that should not make much difference in efficiency, makes it a bit more readable.
In terms of efficiency, this is about as close as you get to efficient, in my opinion. In terms of a cleaner solution, I can't seem to think of one right now. Will update if I think of anything.