Validating specific string in Google App Script - google-apps-script

Situation:
Hi all! I have a Google Spreadsheet which contain two tabs ("Today" and "Current") and I want to validate the values in the cell of last row and column C in "Today" tab (such as C50 or C100, the row number may change) is it equal to the string of "ERROR". If this cell contain the string "ERROR", it will copy the data in the cell of A2:J2 from "Current" tab and replace the "ERROR" string in "Today".
Problem:
Hence, I typed the following code and now it can get the values in "Today" but it failed to validate whether it contains "ERROR" or not. May I know what's wrong with my code? Thank you!
Code:
function checkdata(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Today');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var data = sheet.getSheetValues(lastRow,3,1,1);
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var sheet2 = ss2.getSheetByName('Current');
var values = sheet2.getRange("A2:J2").getValues()[0];
if (data) {
if (data.indexOf('#ERROR!') < 0) {
sheet.getRange(lastRow+1, 1, 1, 10).setValues([[].concat(values)]);
}}}

Modification point:
getSheetValues() returns 2 dimensional array. In this script, the if statement is always true. I thought that this might be the reason of your issue.
Modified script:
From:
var data = sheet.getSheetValues(lastRow,3,1,1);
To:
var data = sheet.getRange(lastRow, 3).getValue();
getValue() returns an object which is not an array. For example, when the value of cell is the string value, the string value is returned. By this, I think that the if statement works.
References:
getSheetValues()
getValue()

May I know what's wrong with my code?
A few issues:
If you want to replace the ERROR string, you need to copy the data from Current into the row where ERROR is located (the last row), not the row beneath it. So:
sheet.getRange(lastRow, 1, 1, 10).setValues([[].concat(values)]);
#ERROR! and ERROR is not the same, so review your situation to decide which is the string you are looking for (if your cell content is #ERROR!, you can find ERROR within it, but not the opposite
sheet.getSheetValues(lastRow,3,1,1); will return you a 2-D value range. In order to use the method indexOf, you need to address a single value of this value range, e.g. data[0][0].indexOf
Alternatively: Define var data = sheet.getRange(lastRow,3,1,1).getValue(); which will directly return you the value, not the value range
The method indexOf is defined in such a way that it return -1 if the value is not found and the position of the value (which is bigger than -1) if the value is found.
So, you need to change indexOf('#ERROR!') < 0 to indexOf('#ERROR!') >= 0
Sample:
function checkdata(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName('Today');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var data = sheet.getSheetValues(lastRow,3,1,1);
var sheet2 = ss.getSheetByName('Current');
var values = sheet2.getRange("A2:J2").getValues()[0];
if (data) {
if (data[0][0].indexOf('#ERROR!') >= 0) {
sheet.getRange(lastRow, 1, 1, 10).setValues([[].concat(values)]);
}}}

Related

Copy and Paste the Row based on condition in another Sheet

I've been looking on this website and others for an answer but can't find anything relevant and was wondering if someone could help please.
I've using Apps Script - Google Sheets.
The main sheet was called "M-Front". So it got quotation number with revision number. If new quotation, the revision will be zero. If we revise the quotation once, the revision number will be 1.
For example, GE-2108-0271-Rev.0 is new quotation.
If we revise once, it would be GE-2108-0271-Rev.1.
I have other sheet called "M-Items".
Let say for GE-2108-0271-Rev.0, we have three rows for that quotation number represent three items for that quotation.
My intention is , if new revision was made in "M-Front". It will be GE-2108-0271-Rev.1. But how to detect the last row from "M-Front" quotation number and in "M-Items" we copy and paste the rows. In this case, 3 rows/items. and make the quotation in "M-Items" from GE-2108-0271-Rev.0 to GE-2108-0271-Rev.1.
M-Front
M-Items
The Script i've stuck
function CopyRange() {
var sourcespread = SpreadsheetApp.openById('1Zgs1jzjIeaBpd5Ms7emQgxhVJBMtlEOlDNDfxlhSRiY'); //replace with source ID
var sourcesheet = sourcespread.getSheetByName('M-Front'); //replace with source Sheet tab name
var destspread = SpreadsheetApp.openById('1Zgs1jzjIeaBpd5Ms7emQgxhVJBMtlEOlDNDfxlhSRiY'); //replace with destination ID
var destsheet = destspread.getSheetByName('M-Items'); //replace with destination Sheet tab name
var testrange = sourcesheet.getRange('M:M').getLastRow;
var testvalue = (testrange.getValues());
var data = [];
var j =[];
for (i=0;i<testvalue.length;i++) {
if (testvalue[i] /= 0) {
data.push.apply(data,sourcesheet.getRange('A:A').getValues());
//Copy matched ROW numbers to j
j.push(i);
}
}
//Copy data array to destination sheet
destsheet.getRange(destsheet.getLastRow()+1,1,data.length,data[0].length).setValues(data);
}
You might want to try the below script:
function CopyRange() {
var sourcespread = SpreadsheetApp.openById('1Zgs1jzjIeaBpd5Ms7emQgxhVJBMtlEOlDNDfxlhSRiY'); //replace with source ID
var sourcesheet = sourcespread.getSheetByName('M-Front'); //replace with source Sheet tab name
var destsheet = sourcespread.getSheetByName('M-Items'); //replace with destination Sheet tab name
var mcol= sourcesheet.getRange('M1:M').getValues();
var acol = sourcesheet.getRange('A1:A').getValues();
var ccol = destsheet.getRange('C1:C').getValues();
var acol2 = destsheet.getRange('A1:A').getValues();
var mvalues = mcol.filter(String);
var avalues = acol.filter(String);
var cvalues = ccol.filter(String);
var avalues2 = acol2.filter(String);
for (let i=1; i<mvalues.length; i++) {
if (mvalues[i][0] != 0) {
if (avalues[i][0] == avalues2[i][0] && mvalues[i][0] == cvalues[i][0] - 1)
var valuescopy = sourcesheet.getRange("RANGE_FOR_THE_VALUES_TO_COPY").getValues();
destsheet.getRange("RANGE_WHERE_TO_PASTE").setValues(valuescopy);
cvalues[i][0]++;
}
}
}
It is important to note the following points:
getLastRow will return the last row for the entire range - this means that the rows which have no values are also included this;
In order to retrieve the rows which contain a value, the filter has been used.
getValues method will return a 2D array, so you will have to access an element in this way array[i][j].
Moreover, please bear in mind that you will have to adjust the ranges properly such that they match your needs accordingly; more specifically, the range from where you want to copy the values and also the destination range.
Reference
getLastRow();
getValues();
getRange(row, column, numRows, numColumns).

How to Make Function Execute Formula on Last Row?

I am trying to use the script editor to allow me to execute the function stored in cell A1 every 24 hours. I want the value that is generated to be stored in cell A2, then the next time the script runs I want that value stored in A3, and so it goes. The problem I am having is that I can't get my code to do this.
I have tried editing the last few lines of the script, but I can not get it to work.
function recordChanges() {
var url = 'LINK TO MY SHEET';
var ss = SpreadsheetApp.openByUrl(url);
var sh = ss.getSheetByName('Sheet1');
var range = sh.getRange("A1");
var values = range.getValues();
var lastRow = sh.getLastRow();
if (values[0][0] != values[1][0]) {
sh.insertRowAfter(lastRow);
sh.getRange().setValue(values[0][0]);
}
}
I expect the script to store the value, and the next time it runs I want it to store the value on the cell below the last store valued. Bonus points if you can get it to place the date the new value was generated in the same row but in column B.
getLastRow only returns the last row of the sheet that contains content.
I am interpreting your question as "how can I copy the value of A1 to the next empty cell in row 1?" My apologies if I am misinterpreting your question, please let me know.
It is unclear what you mean by "execute formula on last row"; please clarify and perhaps show the formula. This code does not make A1 change: I am assuming you already have the value of A1 changing somehow, and all you need to do is copy the current value to the end of row one.
function recordChanges() {
var url = 'LINK TO MY SHEET';
var ss = SpreadsheetApp.openByUrl(url);
var sh = ss.getSheetByName('Sheet1');
var range = sh.getRange("A1");
var firstRow = range.getDataRegion(SpreadsheetApp.Dimension.COLUMNS);
var values = firstRow.getValues();
values[0].push(values[0][0]);
sh.getRange(1, 1, 1, firstRow.getLastColumn() + 1).setValues(values);
}

Copy a row to new sheet based on value in a cell

I'm trying to create a Google Script that copies rows from one Google Sheet into different sheets based on the value of a cell.
The cell value are states in the United States. The master spreadsheet has data from a registration form that is being imported into it all the time. When a new registration happens (and the data is imported into the master sheet), I'd like the script to run and copy that row of data into the appropriate state sheet.
Here's where I'm at:
Get master sheet
Find the last row
Get the value of the cell in the column "state"
Copy that row into one of 50 different sheets depending on what state it is.
Run the script every time the master sheet is updated (via an API).
Any help would be appreciated. I'm definitely a newbie when it comes to scripting and this is just hurting my head.
Here's the code I have so far:
function myFunction() {
// Get Source Spreadsheet
var source = SpreadsheetApp.getActiveSpreadsheet();
// Get Source Sheet from Spreadsheet
var source_sheet = source.getActiveSheet();
// Get Active Range from Sheet
var lastRow = sheet.getLastRow();
// Get the Value of the State Cell
var cellValue = Range.getCell(lastrow,3);
// Copy Last Row to Appropriate State Sheet
if ( cellValue == 'Alaska') {
var target = SpreadsheetApp.openById("");
var target_sheet = target.getSheetByName("Sheet1");
target_sheet.appendRow(lastRow);
}
}
With this code:
// Get Active Range from Sheet
var lastRow = sheet.getLastRow();
The getLastRow() method returns an integer. Then further down in your code, you are using the lastRow variable as the data for appendrow() which won't work;
target_sheet.appendRow(lastRow);
The code should probably be something like this:
var target = SpreadsheetApp.openById("");
var target_sheet = target.getSheetByName("Sheet1");
var lastRowOfData = source_sheet
.getRange(source_sheet.getLastRow(), 1, 1, source_sheet.getLastColumn())
.getValues(); //Returns a two dimensional array
var oneD_Array = lastRowOfData.join().split(","); //Creates a one D array
target_sheet.appendRow(oneD_Array);
The appendRow() method takes a one dimensional array. The getValues() method returns a 2 Dimensional array, so it must be converted. Because you are only getting one row of data, it's easy to convert. The outer array only has one inner array. The one inner array has all the cell values of the row.
Here's the answer for what I came up with for the code:
function myFunction() {
// Get Source Spreadsheet
var source = SpreadsheetApp.getActiveSpreadsheet();
// Get Source Sheet from Spreadsheet
var source_sheet = source.getActiveSheet();
// Get Last Row
var lastRow = source_sheet.getLastRow();
// Get Last Column
var lastColumn = source_sheet.getLastColumn();
// Get Last Row of Data
var lastRowOfData = source_sheet.getRange(lastRow, 1, 1, lastColumn).getValues();
// Creates a one dimensional array
var oneD_array = lastRowOfData.join().split(",");
// Get the Value of the State Cell
var cellValue = source_sheet.getRange(2,7).getValue();
// Copy Last Row to Appropriate State Sheet
if ( cellValue == "New York" ) {
var target = SpreadsheetApp.openById("");
var target_sheet = target.getSheetByName("Sheet1");
target_sheet.appendRow(oneD_array);
}
}

I need to copy format and values from a partial row to a destination in a different sheet (same spreadsheet), function chaining problems?

Trying to copy a partial range in a row using the getActiveRange() & getRow() AND getRange() with a specified range. I have data from a larger spreadsheet "Listings" that needs to be transferred from (getRowIndex, column 4, 1 row tall, 5 columns wide) to the next sheet "ProgressReport" starting under a frozen header. I need to add a row above row 4 in the "ProgressReport" sheet, then paste the format and values from the defined range in the "Listings" sheet. I keep getting a "TypeError" due to either the getRange() or getActiveRange() being "of null". I have checked to see whether or not the range functions have data in the active cells. I have found one answer that seems that it may be pointing me in the right direction by saying that there could be an error because I am using both getActiveRange() & getRow() functions chained together, but I have tried manipulating them so many ways that I simply can't figure it out.
ANY help would and I would be SO grateful!! Thank you in advance! I'll be checking all night because this is bugging me so bad...
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //sheet
var sheet = ss.getSheetByName('Listings!'); //sheet
var activeRange = sheet.getActiveRange().getRowIndex(); //range
var pullRow = activeRange.getRowIndex(); //integer
var copyFrom = activeRange.getRange(pullRow, 4, 1, 5);
var targetSheet = ss.getSheet('ProgressReport!');
var target = targetSheet.getRange(4, 1, 1, 5);
// where PREntry = First row under the frozen header
targetSheet.insertRowsBefore(4, 1);
// This inserts 1 row after the first row (insertAfterRow#, #ofRows)
pullFrom.copyTo(copyFrom, target);
// where (activeRange) = (edited row in listings)
}
I tried to go in and change it up from a different angle; I've gotten all of the way to the last line and there's a "TypeError: Cannot find function copyTo in object xyz" //where "xyz is just the test data that populates the cells I'm testing.
Here is the NEW code that I am trying:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getActiveRange();
var rowStart = range.getRowIndex();
// where getRow retrieves the entire row that has been edited and getRowIndex retrieves the integer for later getSheetValues (below)
var rangeColumn = sheet.getRange("D5:H5");
var columnStart = rangeColumn.getColumn();
var activePartialRow = sheet.getSheetValues(rowStart, columnStart, 1, 5);
// where the partial row is defined by activePartialRow using the integers returned by "columnStart" & "rowStart" vars
var targetSheet = ss.getSheetByName("ProgressReport");
targetSheet.insertRowBefore(4);
// This inserts 1 row after the fourth row (insertAfterRow#, #ofRows)
var target = targetSheet.getRange(4, 1, 1, 5);
// where the target is the first row under the frozen header
activePartialRow.copyTo(target);
// where (activeRange) = (edited row in listings)
}
If anyone can offer an answer to this problem, I'd be extremely grateful! I've searched online, but just can't seem to find anything with what I'm searching! THANK YOU so much in advance! -JH
Just change this line in your code :
var activePartialRow = sheet.getRange(rowStart, columnStart, 1, 5);
// use getRange because we want to get a range object for copyTo()
but apart from that your code could be simplified a bit...
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getActiveRange();
var rowStart = range.getRowIndex();
// where getRow retrieves the entire row that has been edited and getRowIndex retrieves the integer for later getSheetValues (below)
var activePartialRow = sheet.getRange(rowStart, 4, 1, 5);// use getRange because we want to get a range object for copyTo()
// where the partial row is defined by activePartialRow using the integers returned by "columnStart" & "rowStart" vars
var targetSheet = ss.getSheetByName("ProgressReport");
targetSheet.insertRowBefore(4);
// This inserts 1 row after the fourth row (insertAfterRow#, #ofRows)
var target = targetSheet.getRange(4, 1, 1, 5);
// where the target is the first row under the frozen header
activePartialRow.copyTo(target);
// where (activeRange) = (edited row in listings)
}

How to change the contents of an active cell

In a google apps script, I want to be able to enter an integer value (1-10), and then have the script change the cell where that value was entered to a string based on a lookup. Essentially this:
Here's what I have, but it never does anything. I can't even get a cell to change its own text value.
function onEdit(event){
var sheet = event.source.getActiveSheet();
var editedCell = sheet.getActiveCell();
var editedCellRange = SpreadsheetApp.getActiveSheet().getRange(editedCell);
var columnToSortBy = 4;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var Values = [ss.getRange('I2'),ss.getRange('I3'),ss.getRange('I4'),ss.getRange('I5'),ss.getRange('I6'),ss.getRange('I7'),ss.getRange('I8'),ss.getRange('I9'),ss.getRange('I10'),ss.getRange('I11')];
if(editedCell.getColumn() == columnToSortBy){
editedCellRange.setValue(Values[editedCellRange.getValue()-1]);
}
}
So var Values is an array holding the string values that should be displayed. When a cell in the 4th column is edited to contain an integer, then the script should look up the value of that integer position in the array, and then put the appropriate string in the edited cell. Can anyone show me what is wrong with my script (or a better way to write this in a script)?
First, Values is an array of Range objects. When you are doing
editedCellRange.setValue(Values[editedCellRange.getValue()-1]);
you're trying to pass a Range object to setValue which is incorrect. So, I'd change it to something like this
var range = sheet.getRange("I2:I11");
var Values = range.getValues();
if(editedCell.getColumn() == columnToSortBy){
var number = parseInt(editedCellRange.getValue());
editedCellRange.setValue(Values[number -1][0]);
}