Formula to edit a cell based on if-else condition - google-apps-script

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 :)

Related

Function that loops through the sheet

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

Google Sheet script to hide columns by date

I'm essentially trying to do exactly what was done in this question, but with columns instead of rows. When I run the script there as is, it works fine. But just switching all references to columns to rows (and vice versa) isn't working for me, for some reason, and I can't figure out what's wrong.
For reference, this is what I have:
function onOpen()
{
var ui = SpreadsheetApp.getUi();
ui.createMenu('My Tools')
.addItem('Hide Columns','hideColumnsDate')
.addToUi();
}
function hideColumnsDate(row)
{
var row = (typeof(row) !== 'undefined') ? row : '1';
var day = 86400000;
var today = new Date().getTime();
var rng = SpreadsheetApp.getActiveSheet().getRange(row + ':' + row);
var rngA = rng.getValues();
for(var i = 0; i < rngA.length ;i++)
{
if(isDate(rngA[i][0]) && (((today - new Date(rngA[i][0]).getTime())/day) > 7 ))
{
SpreadsheetApp.getActiveSheet().hideColumns(i + 1);
}
}
}
function isDate (x)
{
return (null != x) && !isNaN(x) && ("undefined" !== typeof x.getDate);
}
When your script is modified, how about this modification? Please think of this as just one of several modifications.
Modification points:
In your situation, the values retrieved from the range of SpreadsheetApp.getActiveSheet().getRange(row + ':' + row) is [[column1, column2, column3,,,]].
In this case, the length of the for loop is rngA[0].length.
In order to retrieve the values of the columns, please modify rngA[i][0] to rngA[0][i].
Modified script:
From:
for(var i = 0; i < rngA.length ;i++)
{
if(isDate(rngA[i][0]) && (((today - new Date(rngA[i][0]).getTime())/day) > 7 ))
To:
for(var i = 0; i < rngA[0].length ;i++)
{
if(isDate(rngA[0][i]) && (((today - new Date(rngA[0][i]).getTime())/day) > 7 ))
Note:
In your case, as other pattern, you can also use the following modification.
Modify var rngA = rng.getValues(); to var rngA = rng.getValues()[0];, and modify rngA[i][0] to rngA[i].
In above modified script, all rows of a column are checked. If you want to check the specific columns, please tell me.
Reference:
getValues()
If this was not the result you want, I apologize.
function hideColumnsDate(row) {
var row=row||1;
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getRange(row,1,1,sh.getLastColumn());
var vA=rg.getValues()[0];
var today=new Date().valueOf();
vA.forEach(function(e,i){
var rowdate=new Date(e).valueOf();
if(((today-rowdate)/86400000)>7) {
sh.hideColumns(i+1);
}
});
}

How can I make a Google Sheet script run reliably on Samsung tablets?

I have two functions in my Google Sheet script which are each triggered by means of a checkbox (since Google Sheets on mobile can't use images as buttons). They work on PC (rather slowly), but on tablets, they tend to fail more often than not, which then also affects PC users.
The script is set up to perform an onEdit check of two checkbox cells. If the checkbox in cell C3 is checked, the AUTOFILL function should run (which displays the A cell value of the last row on the Info sheet plus 1 in cell C4 of the Data Entry sheet, and then clears the checkbox), and if the checkbox in cell C12 is checked, the SUBMIT function should run (which takes the range of data entered on the Data Entry sheet and updates an existing row/adds a new row on the Data sheet with the information from the Data Entry sheet, adding a timestamp if cell C11 on the Data Entry sheet contains the word 'CLEANED', and then clears the checkbox).
I've tried experimenting with various WIFI signal strengths and more powerful tablets, but I am unable to pinpoint the exact culprit here - sometimes this will run, most often the checkbox will just remain checked and nothing happens. Laptops and desktop computers all seem to run, but if a tablet tries to run and fails, the computers will sometimes not run either, until I go into the script itself and manually force once of the functions to run, which seems to reset things and lets the computers work again.
Is it because of the processing required in order to run this code? I've tried to optimize it as much as possible, but is there something else that I might change here which would make this work, every time?
Here is the example sheet, and here is the script:
function onEdit(e) {
if (e.range.getSheet().getName() != "Data Entry") {
return
}
var isAutofill = SpreadsheetApp.getActiveSheet().getRange("C3").getValue();
var isSubmit = SpreadsheetApp.getActiveSheet().getRange("C12").getValue();
if (isAutofill && isSubmit) {
Browser.msgBox("You cannot autofill and submit data at the same time!");
SpreadsheetApp.getActiveSheet().getRange("C3").setValue(false);
SpreadsheetApp.getActiveSheet().getRange("C12").setValue(false);
} else if (isAutofill) {
AUTOFILL();
SpreadsheetApp.getActiveSheet().getRange("C3").setValue(false);
} else if (isSubmit) {
SUBMIT();
SpreadsheetApp.getActiveSheet().getRange("C12").setValue(false);
}
}
function AUTOFILL() {
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Info');
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Data Entry');
var valueOfData = sheet1.getRange(sheet1.getLastRow(), 1).getValue();
sheet2.getRange('C4').setValue(valueOfData + 1);
}
function SUBMIT() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formSS = ss.getSheetByName("Data Entry");
var dataSheet = ss.getSheetByName("Info");
var values = formSS.getRange("C4:C11").getValues().reduce(function(a, b) {
return a.concat(b)
});
var partNum = values[0];
var row;
dataSheet.getDataRange().getValues().forEach(function(r, i) {
if (r[0] === partNum) {
row = i + 1
}
})
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 8).getValues()[0].map(function (el, ind){
return el = values[ind] ? values[ind] : el;
})
var statusValue = formSS.getRange("C11").getValue();
if (statusValue != 'CLEANED') {
dataSheet.getRange(row, 1, 1, 8).setValues([data]);
}
if (statusValue == 'CLEANED') {
var now = [new Date()];
var newData = data.concat(now)
dataSheet.getRange(row, 1, 1, 9).setValues([newData]);
}
formSS.getRange("C4:C11").clearContent()
}
I made a few changes. Take a look. Hopefully you can use them to speed up the function.
function onEdit(e) {
var sh=e.range.getSheet();
if (sh.getName() != "Data Entry") {return;}
var rgC3=SpreadsheetApp.getActiveSheet().getRange("C3");
var rgC12=SpreadsheetApp.getActiveSheet().getRange("C12");
var isAutofill = rgC3.getValue();
var isSubmit = rgC12.getValue();
if (isAutofill && isSubmit) {
e.source.toast("You cannot autofill and submit data at the same time!");
rgC3.setValue(false);
rgC12.setValue(false);
} else if (isAutofill) {
AUTOFILL(e.source);
rgC3.setValue(false);
} else if (isSubmit) {
SUBMIT(e.source);
rgC12.setValue(false);
}
}
function AUTOFILL(ss) {
var sheet1 = ss.getSheetByName('Info');
var sheet2 = ss.getSheetByName('Data Entry');
var valueOfData = sheet1.getRange(sheet1.getLastRow(), 1).getValue();
sheet2.getRange('C4').setValue(valueOfData + 1);
}
function SUBMIT(ss) {
var formSS=ss.getSheetByName("Data Entry");
var dataSheet=ss.getSheetByName("Info");
var values=formSS.getRange("C4:C11").getValues().reduce(function(a, b) {return a.concat(b)});
var partNum = values[0];
var row;
var data=dataSheet.getDataRange().getValues()
for(var i=0;i<data.length;i++) {
if(data[i][0]==partNum) {
row=i+1;
break;
}
}
row = row ? row : dataSheet.getLastRow() + 1;
var data = dataSheet.getRange(row, 1, 1, 8).getValues()[0].map(function (el, ind){return el = values[ind] ? values[ind] : el;})
var statusValue = formSS.getRange("C11").getValue();
if (statusValue != 'CLEANED') {dataSheet.getRange(row, 1, 1, 8).setValues([data]);}
if (statusValue == 'CLEANED') {var now = [new Date()];var newData=data.concat(now);dataSheet.getRange(row, 1, 1, 9).setValues([newData]);}
formSS.getRange("C4:C11").clearContent();
}

Script for Google sheet to change a cells value based on another cells value (in a column range)

Here is the scenario:
Column E in my Googlesheet has a dropdown list of Yes and No. Everytime the user answers No, I want the corresponding cell in Column G to have the words "Not Applicable". But if user answers Yes, I want that cell in G to have another dropdown list of Yes and No.
I tried to build on the script that I got from this thread:
Google Sheets formula to change a cells value based on another cells value
It's almost perfect, but I can't make it to work for a range (an entire column, preferrably). Any advice would be appreciated :)
Since I wasn't getting any success trying to tweak it for my own use, here's a copy code from the mentioned thread:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getActiveSheet()
var nota=e.range.getA1Notation()
if(nota=="E10"){
var val=e.range.getValue()
if(val=="Levy"){
s.getRange("E11").setDataValidation(null)
s.getRange("E11").setValue("Monthly")
}
else{
s.getRange('E11').clearContent()
var cell = s.getRange('E11');
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['Triannual', 'Quarterly']).build();
cell.setDataValidation(rule);
}}}
And here's my dumb attempt:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var s=ss.getActiveSheet()
var nota=e.range.getA1Notation()
if(nota=="E2:E500"){
var val=e.range.getValue()
if(val=="No"){
s.getRange("G2:G500").setDataValidation(null)
s.getRange("G2:G500").setValue("Not Applicable")
}
else{
s.getRange('G2:G500').clearContent()
var cell = s.getRange('G2:G500');
var rule = SpreadsheetApp.newDataValidation().requireValueInList(['Yes','No']).build();
cell.setDataValidation(rule);
}}}
You need to loop a range of cells, which is why the original script isn't working. .getValue() returns a single cell, you can't have a range (as in your edited script).
This script will look at the entire page and loop it each time. This is preferable because you don't have to keep data in order. In other words, you can jump around Column E and mark things "Yes" or "No" as they come up. Blank cells are ignored.
function addValidation() {
// Get the spreadsheet and active sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Get the data as an Array you can iterate and manipulate
var data = sheet.getDataRange().getValues();
// Store a rule to use for the Data Validation to be added if ColE == "Yes"
var rule = SpreadsheetApp.newDataValidation().requireValueInList(["Yes", "No"]).build();
// Loop the sheet
for(var i=0; i<data.length; i++) {
// Test ColE. Note that the array is 0-indexed, so A=0, B=2, etc...
// To change which columns you're testing, change the second value.
if(data[i][4] == "Yes") {
// If it's "Yes," add the Data Validation rule to Col G for that row.
// Note that .getRange() is _not_ 0 indexed, which is why you need `i+1` to get the correct row
sheet.getRange(i+1, 7).clear().setDataValidation(rule);
// If ColE == "No," mark ColG as "Not Applicable"
} else if(data[i][4] == "No") {
sheet.getRange(i+1, 7).clearDataValidations().setValue("Not Applicable");
}
}
}
Also note that this will change values as you change Col E. So, if you change a "Yes" to a "No," Col G will be changed to "Not Applicable."
for (var i = 0; i < 5000; i++) {
function checkData() {
if(SpreadsheetApp.getActiveSheet().getRange("E" + i).getValue() == "No"){
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Not Applicable');
}
else{
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Applicable');
}
}
}
Hope this works for you:)
Btw getting the range of 5000 rows will be VERY slow! Here is another way you can do it faster!
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tsSheet = ss.getSheetByName("YOUR SHEET NAME AT THE BOTTOM OF THE PAGE");
var tsRows = parseInt(tsSheet.getLastRow());
for (var i = 0; i < tsRows; i++) {
function checkData() {
if(SpreadsheetApp.getActiveSheet().getRange("E" + i).getValue() == "No"){
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Not Applicable');
}
else{
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Applicable');
}
}
}
EDIT:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tsSheet = ss.getSheetByName("YOUR SHEET NAME AT THE BOTTOM OF THE PAGE");
var tsRows = parseInt(tsSheet.getLastRow());
for (var i = 0; i < tsRows + 1; i++) {
function checkData() {
if(SpreadsheetApp.getActiveSheet().getRange("E" + i).getValue() == "No"){
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Not Applicable');
}
else{
SpreadsheetApp.getActiveSheet().getRange("G" + i).setValue('Applicable');
}
}
}

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.