Function that loops through the sheet - google-apps-script

I'm trying to make Apps Script macro that will do following:
Check if checkmark (cell value = TRUE/FALSE) is ticked in column A
If it's ticked, increase value of cell in column H
Repeat until reached the last row.
After a little bit of digging around in documentation, I came up with this, and from my understanding it should be working, but since I'm asking a question here, it obviously does not. Script does get executed without errors, but it changes nothing on the sheet.
function increment() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var EndRow = ss.getLastRow();
for (var i = 2; i <= EndRow; i++) {
var Cell = ss.getRange(i,8);
var CheckmarkCell = ss.getRange(i,1);
if (CheckmarkCell.getValue() == 'TRUE') {
ss.Cell.setValue(ss.Cell.getValue() + 1);
}
}
}
Anyone has any idea, what's wrong here?

See if this helps?
function increMentWhenTrue() {
const sh = SpreadsheetApp.getActive().getSheetByName('Sheet1').getDataRange().offset(2, 0)
const values = sh.getValues().map(r => {
r[7] = (r[0]) ? (r[7]) ? r[7]+1 : 1 : r[7];
return r;
})
sh.setValues(values);
}
Change the sheet name in the first line to suit your requirements.
Same code with if-else statements
function increMentWhenTrue() {
const sh = SpreadsheetApp.getActive().getSheetByName('Blad1').getDataRange().offset(2, 0)
const values = sh.getValues().map(r => {
if (r[0]) {
if (r[7]) {
r[7] = r[7] + 1;
} else {
r[7] = 1;
}
} else {
r[7] = r[7];
}
return r;
})
sh.setValues(values);
}

Related

Identifying number in an array and empty values in google apps script

I have a simple column in column A in a sheet by name Sno. (serial number). I am trying to read the column and identify -
-if there are any empty cells from first cell in the column to the last filled row and
-if the values which are present are numbers only
This will help me do 2 validations, to identify empty cells in between the cell values, like if there are 1 - 200 numbers entered then in between there are no misses in the series and if the values which are present all numbers
I tried the below to check that but not getting it right-
unction siteShieldmaps() {
SS = SpreadsheetApp.getActiveSpreadsheet();
var SS_m = SS.getSheetByName("Cleanup sheet");
var LAST_ROW = SS_m.getLastRow();
console.log(LAST_ROW);
var Sno_values = SS_m.getRange(`A1:A${LAST_ROW}`).getDisplayValues().toString();
console.log(typeof Sno_values);
var result = isNumberOrEmpty(Sno_values);
console.log(result);
}
function isNumberOrEmpty(array) {
var result = [];
for (var i = 0; i < array.length; i++) {
if (array[i] === "") {
result.push("empty");
} else if (!isNaN(array[i])) {
result.push("number");
} else {
result.push("not a number");
}
}
return result;
}
Please guide
Adding to the comment of #TheWizEd, one of the issues of the code is how the array has been called. I made other changes in the code to make sure that both validations are completed.
Make sure if there are any empty cells.
Make sure that all the values are numbers.
Here is the table I made for testing:
Here is the sample code:
function siteShieldmaps() {
ss = SpreadsheetApp.getActiveSpreadsheet();
let ss_m = ss.getSheetByName("Sheet1");
let last_row = ss_m.getLastRow();
console.log(last_row);
// change how the range is call from "A1:A${LAST_ROW} to "2,1,last_row"
// The range "2,1,last_row" will exclude the "A1" cell
// Also, I change "getDisplayValues().toString();" to "getValues()"
// if you keep "getDisplayValues().toString();"
//it will show some cells as not number when they are
let sno_values = ss_m.getRange(2,1,last_row).getValues();
let result = isNumberOrEmpty(sno_values);
console.log(result);
}
function isNumberOrEmpty(array) {
let result = [];
for (let i = 0; i < array.length; i++) {
// create the variable row instead of using array[i][0]
// so I use row[0] in the if statement
let row = array[i]
if (row[0] === "") {
result.push("empty");
} else if (!isNaN(row[0])) {
result.push("number");
} else {
result.push("not a number");
}
}
return result;
}
And the result will be:
I would really comment instead of posting but I don't have enough reputation.
In this line of code you're not actually getting a 2-D array but a string.
var Sno_values = SS_m.getRange(`A1:A${LAST_ROW}`).getDisplayValues().toString();
toString()
It should be just
var Sno_values = SS_m.getRange(`A1:A${LAST_ROW}`).getDisplayValues()
Besides, as TheWizEd remarked you are working with a 2D array, so your function should be:
function isNumberOrEmpty(array) {
var result = [];
for (var i = 0; i < array.length; i++) {
if (array[i][0] === "") {
result.push("empty");
} else if (!isNaN(array[i][0])) {
result.push("number");
} else {
result.push("not a number");
}
}
return result;
}

My google app script takes longer to run how can I minimize the run time?

function test() {
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var ss = ss1.getActiveSheet();
var only = ['AutoGR', 'Sheet2', 'Sheet3', 'Sheet4'];
if (only.indexOf(ss.getName()) == -1) return;
var numRows = SpreadsheetApp.getActiveSheet().getLastRow();
var range;
for (var i = 1; i <= numRows; i++) {
range = ss.getRange('B' + i);
if (range.getValues() == "Crate") {
range.offset(0, 4).setValue(3000);
}
}
for (var i = 1; i <= numRows; i++) {
range = ss.getRange('B' + i);
if (range.getValues() == "Pallet") {
range.offset(0, 4).setValue(4200);
}
}
}
What I am trying to achieve is if values in column B = ‘Crate’ then in the same row under column named Qty put value automatically as 3000, if values in column B = ‘Pallet’ then Qty column automatically gets updated as 4200 but when B=‘close operation’ I have to add qty manually.
Setting Column F in multiple sheets using getValues() and setValues()
function test() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const incl = ['AutoGR', 'Sheet2', 'Sheet3', 'Sheet4'];
const shts = ss.getSheets().filter(sh => ~incl.indexOf(sh.getName()));
shts.forEach(sh => {
let bs = sh.getRange(1,2,sh.getLastRow()).getValues();
let fs = sh.getRange(1,6,sh.getLastRow()).getValues();
bs.forEach((r,i) => {
if(r[0] == "Crate") {
fs[i][0] = 3000;
} else if(r[0] == "Pallet") {
fs[i][0] = 4200;
}
})
sh.getRange(1,6,fs.length,1).setValues(fs);
})
}
If this causes problems in other cells in F then you may be forced to write to F one cell at a time but you'll still get better performance on the read side.

Formula to edit a cell based on if-else condition

I am planning to create a cell where if the cells in G2 is empty then it will copy the content from row A but if the cell in column G is updated with something else I dont want to copy the content from row A. I have done code something like this in App Script but it is not working.
function getLast(range) {
var getResult = function(range) {
if (!((range.getNumRows() > 1 && range.getNumColumns() == 1) || (range.getNumRows() == 1 && range.getNumColumns() > 1))) {
throw new Error("Please input one row or one column.");
}
var v = Array.prototype.concat.apply([], range.getValues());
var f = Array.prototype.concat.apply([], range.getFormulas());
var i;
for (i = v.length - 1; i >= 0; i--) {
if (v[i] != "" || f[i] != "") break;
}
return i + 1;
};
if (Array.isArray(range)) {
return range.map(function(e) {
return getResult(e);
});
} else {
try {
range.getA1Notation();
} catch (e) {
throw new Error("Inputted value is not a range.");
}
return getResult(range);
}
}
function formulasheets(){
var ss = SpreadsheetApp.openByUrl(url);
var sheet = ss.getSheetByName("USERNAMES");
sheet.getRange("G2").setFormula('=IF(G2="",A2, ');
var range1 = sheet.getRange("B:B");
var fillDownRangecolumnI = sheet.getRange(2, 7, lr-1);
sheet.getRange("G2").copyTo(fillDownRangecolumnA);
}
I have attached the image of my google sheet to explain better on what I want. Can ayone help me on this. Thank you.
If Cell G2 & G5 is empty
It should be updated with content in row A
I see your question, and I would like to give a try, hope it is useful for you. Please refer to my edited code below, I think it is better for you to use for loop to check for blank, and to avoid write formula:
function formulasheets(){
var ss = SpreadsheetApp.openByUrl(url);
var sheet = ss.getSheetByName("USERNAMES");
for (var x=1;x <= sheet.getLastRow();x++){
var cell = sheet.getRange(x,7);
if (cell.isBlank()){
sheet.getRange(x,1).copyTo(cell);
}
}
}
Before execution
After execution, accept if help, it is my first time answer G Apps Script :)

Use formula inside script

I would like to use a formula inside a custom function, like this for example:
function myFunction(range, value) {
var countNumber = COUNTIF(range; value); // COUNTIF is a formula that can be used in the spreadsheet
if (countNumber > 0) {
return "RESULT";
} else {
return "OTHER RESULT";
}
}
And then:
=MYFUNCTION(A1:A5,"VALUETOTEST")
I would like to simplify a huge formula:
Something like:
=IF(SUM(COUNTIFS(G182:G186;"ERROR";H182:H186;"62");COUNTIFS(G182:G186;"ERROR";H182:H186;"ALL"))>0;"ERRO";IF(SUM(COUNTIFS(G182:G186;"RETEST";H182:H186;"62");COUNTIFS(G182:G186;"RETEST";H182:H186;"TODOS"))>0;"RETEST";IF(COUNTIF(G182:G186;"UNIMPLEMENTED")>0;"UNIMPLEMENTED";"SOLVED")))
You have three ways of performing these actions.
Add the Sheet Formulas to the sheet itself in the ranges that you need. Then read the data from the result cells (wherever you set it to write to) using your GAS Function. You can then perform further processing using the results.
Use your GAS function to write Sheet Formulas into your sheet. Then use more GAS to read that result and process the data. The method for this can be found here: https://developers.google.com/apps-script/reference/spreadsheet/range#setFormula(String)
You can create a Custom Sheet Formula using GAS that you then use in your sheet. GAS can then read that result and process the information. This will require some research into JS as a whole to know how to recreate, combine, and perform the operations that you need the data in the sheet to perform.
You can find a guide to make Custom Formulas here: https://developers.google.com/apps-script/guides/sheets/functions
And a guide to JS here: http://www.w3schools.com/js/default.asp
W3 Schools has a quite comprehensive guide to JS. GAS uses all native JS methods as it is a JS coding environment. Check the GAS Reference for more on GAS-specific methods that may perform what you need.
If what you need is to check conditions and/or iterate through rows, try something like this:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange(startRow, startColumn, numRows, numColumns);
var values = range.getValues(); //This is a 2D array; iterate appropriately
for (i = 0; i < values.length; i++) {
if (values[i] == conditionToCheck) {
//perform code..OR
//continue; <- This works to skip the row if the condition is met
} else {
//perform alternate code if condition is not met
}
}
}
As I mentioned, .getValues() creates a 2D array. If you need to iterate through columns and rows, you will need 2 for() loops like so:
for (i = 0; i < values.length; i++) { //iterates through the rows
for(j = 0; j < values[i].length; j++) { //iterates through the columns in that current row
It is important to mention how GAS handles 2D arrays. values[i][j] denotes how much i rows there are and j columns. You can visualize like so:
values = [[A1, B1, C1],[A2, B2, C2],[A3, B3, C3]]
This is an array of arrays where the outer array is an array of the rows, while the insides are an array of cell values by column in that row.
Custom functions in google apps script do not have access to spreadsheet function. You may try using this =IF(COUNTIF(A1:A5,"VALUETOTEST")>0,"RESULT","OTHER RESULT")
If there is a huge formula for result, try creating functions for the result
function result1() {
return "RESULT";
}
function result2() {
return "OTHER RESULT";
}
Then use this =IF(COUNTIF(A1:A5,"VALUETOTEST")>0,RESULT1(),RESULT2())
Try this - copy the below function in apps script, and use this as Formula =myFunction("G182:G186","H182:H186") remeber to ensclose the range with ' " ' because you will be passing the range as string, and note both the ranges must be of equal length.
function myFunction(aRange, bRange) {
var cond_1 = "ERROR";
var cond_2 = "62";
var cond_3 = "ALL";
var cond_4 = "RETEST";
var cond_5 = "TODOS";
var cond_6 = "UNIMPLEMENTED";
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var aRange = sheet.getRange(aRange);
var aValues = aRange.getValues();
var bRange = sheet.getRange(bRange);
var bValues = bRange.getValues();
var count = 0;
var tmplength = 0;
if (aValues.length != bValues.length) {
return "Range length does not Match";
}
for (i = 0; i < aValues.length; i++) {
if (aValues[i] == cond_1 && bValues[i] == cond_2) {
count += 1;
}
if (aValues[i] == cond_1 && bValues[i] == cond_3) {
count += 1;
}
if (count > 0) {
return "ERROR";
} else {
count = 0;
if (aValues[i] == cond_4 && bValues[i] == cond_2) {
count += 1;
}
if (aValues[i] == cond_4 && bValues[i] == cond_5) {
count += 1;
}
if (count > 0) {
return "RETEST";
} else {
count = 0;
if (aValues[i] == cond_6) {
count += 1;
}
if (count > 0) {
return "UNIMPLEMENTED";
} else {
return "SOLVED";
}
}
}
}
}
This is how I solved my problem. I thank to people who helped me to reach this result!
// Like COUNTIFS
var countConditionals = function(cells, condition1, condition2) {
var count = 0;
for (i = 0; i < cells.length; i++) {
if (cells[i][0] == condition1 && cells[i][1] == condition2) {
count++;
}
}
return count;
}
// Like COUNTIF
var countConditional = function(cells, condition) {
var count = 0;
for (i = 0; i < cells.length; i++) {
if (cells[i][0] == condition) {
count++;
}
}
return count;
}
//Whole Formula
function verificaStatus(cells, db) {
const ERROR = "ERROR";
const ALL = "ALL";
const RETEST = "RETEST";
const NOTYET = "UNIMPLEMENTADED";
const SOLVED = "SOLVED";
var countErrors = countConditionals(cells, ERROR, db);
var countErrorsAll = countConditionals(cells, ERROR, ALL);
var sumErrors = countErrors + countErrorsAll;
if (sumErrors > 0) {
return ERROR;
} else {
var retest = countConditionals(cells, RETEST, db);
var retestAll = countConditionals(cells, RETEST, db);
var sumRetest = retest + retestAll;
if (sumRetest > 0) {
return RETEST;
} else {
var countNonCreated = countConditional(cells, NOTYET);
if (countNonCreated > 0) {
return NOTYET;
}
}
}
return SOLVED;
}

How to change a google spreadsheet row color, when a cell in the row is edited?

I have already tried this: Script to Change Row Color when a cell changes text but it can't get it to work. The color of the row does not change to #000000. This is what I have so far:
function onEdit(event)
{
var ss = event.source.getActiveSheet();
var r = event.source.getActiveRange();
var currentValue = r.getValue();
if(currentValue == "dags dato")
{
var dd = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd");
r.setValue(dd);
}
else if(currentValue == "dialog")
{
setRowColor("yellow");
}
else if(currentValue == "besvaret")
{
setRowColor("yellow");
}
else if(currentValue == "afvist")
{
setRowColor("red");
}
}
function setRowColor(color)
{
var range = SpreadsheetApp.getActiveSheet().getDataRange();
var statusColumnOffset = getStatusColumnOffset();
for (var i = range.getRow(); i < range.getLastRow(); i++) {
rowRange = range.offset(i, 0, 1);
status = rowRange.offset(0, statusColumnOffset).getValue();
rowRange.setBackgroundColor("#000000");
}
//Returns the offset value of the column titled "Status"
//(eg, if the 7th column is labeled "Status", this function returns 6)
function getStatusColumnOffset() {
lastColumn = SpreadsheetApp.getActiveSheet().getLastColumn();
var range = SpreadsheetApp.getActiveSheet().getRange(1,1,1,lastColumn);
for (var i = 0; i < range.getLastColumn(); i++) {
if (range.offset(0, i, 1, 1).getValue() == "Status") {
return i;
}
}
}
I wrote way faster and cleaner method for myself and I wanted to share it.
function onEdit(e) {
if (e) {
var ss = e.source.getActiveSheet();
var r = e.source.getActiveRange();
// If you want to be specific
// do not work in first row
// do not work in other sheets except "MySheet"
if (r.getRow() != 1 && ss.getName() == "MySheet") {
// E.g. status column is 2nd (B)
status = ss.getRange(r.getRow(), 2).getValue();
// Specify the range with which You want to highlight
// with some reading of API you can easily modify the range selection properties
// (e.g. to automatically select all columns)
rowRange = ss.getRange(r.getRow(),1,1,19);
// This changes font color
if (status == 'YES') {
rowRange.setFontColor("#999999");
} else if (status == 'N/A') {
rowRange.setFontColor("#999999");
// DEFAULT
} else if (status == '') {
rowRange.setFontColor("#000000");
}
}
}
}
You could try to check your code for any errors or issues by using the Logger class like so:
try {
//your code
}
catch(e) {
Logger.log(e);
}
Then you can go to View -> Logs from the Script Editor to see if each line of code performs as expected. Also the Execution transcript might be useful to see if the code breaks at one particular line of code. You can view more details about how each troubleshooting method works.