How to change the contents of an active cell - google-apps-script

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]);
}

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 use offset after obtaining reference cell using indexOf in Google Script

I've written a script to find a match of a given cell via for loop variable (it works great). When logged out, it provides the position 11.0 in the searched column of data. What I then want to do is uncheck a checkbox that is offset by (0,-5) from that referenced cell. When I try to use offset, I get the TypeError: offset is not a function. How do I accomplish this?
Below is the script I've written to get to where I am stuck. What I am doing is checking a box on Sheet2, which is on the same row for a given product. The row on which the product and its checkbox reside will not always be the same (could be row 5, could be row 12). Once I check the box, the script determines what the name of the product is (in this case, Product L), and then looks for its match via indexOf on Sheet1. IndexOf finds the location on Sheet1 (in this case, 11.0, which is row 13, col 10). There is a corresponding checkbox on Sheet1 row 13 in column 5 which then needs to be unchecked. And that is where I am stuck. The sheet is dynamic, and the rows for checkboxes and corresponding products will constantly be changing.
function findText() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet2 = spreadsheet.getSheetByName("Sheet2");
var sheet1 = spreadsheet.getSheetByName("Sheet1");
var lr = sheet1.getLastRow();
var lookupRangeArray = sheet1.getRange(3,10,lr,1).getValues();
var newRange = lookupRangeArray.map(function(r){ return r[0]; });
for (var i=0; i <= lr; i++){
var checkboxRange = sheet2.getRange(i+1,2);
var checkboxStatus = checkboxRange.getValue();
if(checkboxStatus == true){
var text = checkboxRange.offset(0, 2).getValue();
Logger.log(text);
var position = newRange.indexOf(text);
Logger.log(position)
position.offset(0,-5).setValue(false);
You need to retrieve the cell to offset
You can do it e.g. by specifying the row and column position of the cell reference or its A1 notation.
Sample
var row=1;
var column = 11;
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var cell = sheet.getRange(row, column);
var newCell = cell.offset(0, -5);

Validating specific string in Google App 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)]);
}}}

google sheet script doesn't enter the second for loop

I'm doing a loop in google sheets script, i'm trying to find a row in the "Inventar" sheet that has the same value found in the sheet "Fisa client" and then change the value of a cell in that row but it appears that it does not enter the second for. I'm new to this so i don't know what's the problem.
function adaugabucati1(){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var ss=sheet.getSheetByName('Fisa client');
var ss2=sheet.getSheetByName('Inventar');
var data = ss.getRange("g9:l18").getValues();
var data1=ss2.getDataRange().getValue();
for(var i=0;i<data.length;i++){
if(!data[i][0] == ""){
var cod = ss.getRange(i+9,8).getValue();
var buc = ss.getRange(i+9,10).getValue();
for(var y=0;y<data1.length;y++){
if(data1[y][5] == cod){
var bucati = data[y][7]-buc;
ss2.getRange(y+1,8).setValue(bucati);
}
}
}
}
}
The problem is in this line:
var data1=ss2.getDataRange().getValue();
getValue() returns only one value - the value of the top-left cell in the range.
When the if statement following the second loop evaluates data1[y][5], it returns "undefined" and the rest of the second loop is bypassed.
You need to change line#6 to:
var data1=ss2.getDataRange().getValues();
Note getValue() - > getValues()

Google Sheets Script - Reference a specific cell in a row

I have a sheet where when I change a specific cell to "YES", I need a template sheet to be copied to a new version and named as per the value of a cell on the current row.
I'm having trouble working out how to get the value of the first cell in the row selected. This is what I have so far (I know this is wrong):
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = sheet.getCurrentCell();
if (currentCell = "YES")
{
SpreadsheetApp.getActiveSpreadsheet().toast("New change control sheet added to workbook.","Change Control",15);
var sourceRow = ss.getActiveRange().getRowIndex();
var tabName = ss.getRange(cell,1).getValues();
ss.getSheetByName("CCTemplate").showSheet()
.activate();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.duplicateActiveSheet();
ss.setActiveSheet(ss.getSheetByName('CCTemplate'), true);
ss.getActiveSheet().hideSheet();
ss.setActiveSheet(ss.getSheetByName('Copy of CCTemplate'), true);
ss.getActiveSheet().setName("CC" & tabName);
}
}
Any ideas?
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=='Your Sheet Name' && e.value=="YES") {
e.source.toast="New change control sheet added to workbook.","Change Control",15);
var tabName=sh.getRange(e.range.rowStart,1).getValue();
var tsh=e.source.getSheetByName('CCTemplate');
var csh=tsh.copyTo(e.source);
csh.setName('CC'+tabName);
}
}
You should avoid using activate in your scripts especially in simple triggers where you have to finish in 30 seconds. I think this code does the same thing that you intended for your code. One significant difference is that I use the information that comes in the event object that comes with the trigger. You should add the code Logger.log(JSON.stringify(e)) and then look at the logs you will see that there is a lot of information available to you which removes the need to run extra functions to get things like a spreadsheet.
Use event objects
onEdit offers among others the event objects range and value which are helpful to retrieve the range that has been edited and its value.
Also
When you want to a cell and compare it against a value, like in if (currentCell = "YES") - you need to retrive its value (either currentCell.getValue() or just event.value) and you need to use == instead of = for comparison.
Be careful with getValues() vs getValue(). The former gives you a 2D array and is not necessary if you want to retrieve the value of a single cell.
There is no need to set your sheet to active in order to change its name.
You can rewrite your code as following:
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var currentCell = event.range;
var value = event.value;
if (value == "YES")
{
...
var sourceRow = range.getRowIndex();
var tabName = ss.getRange(sourceRow, 1).getValue();
...
ss.getSheetByName('Copy of CCTemplate').setName("CC" + tabName);
}
}