Copy cell if certain condition met - if-statement

I know there are already many topics like mine, but I am completely new to programming scripts and therefore I ask you to help me with following problem:
In cell B2 is the user name and in cell C2 the submitter type - if the submitter type is "Requester" then the user name of cell B2 should be copied to cell AE2 - the problem is, that I also want to keep the previous user names if the submitter type change and gets updated...
That means, first the submitter type is "Requester" then the system should copy the user name to cell AE2 - if the submitter type of my line change, then the already copied user name should not change - understood what I want? This should work for all lines of the spreadsheet...
I tried the code but got following error:
Maybe you can improve the code for me?
I changed those 2:
Before:
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
After:
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
The error now is:
new error
Or was the change wrong? Maybe you mean that:
var userNameColumn = 2; //Column where the user name is written
var subTypeColumn = 5; //Column where the submitter type is written ex. "Requester"
var sUserNameColumn = 3; //Column where the user name is saved
But then only one object (username) is known instead of 2 before - subTypeCell and sUserNameCell again undefined - that says the debugger - the code looks now like that (again with my changes, because then 2 objects instead only 1 is known):

You can do something like this:
var userNameColumn = 2; //Column where the user name is written
var subTypeColumn = 3; //Column where the submitter type is written ex. "Requester"
var sUserNameColumn = 5; //Column where the user name is saved
function saveUserName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
if(sUserNameCell.isBlank() && subTypeCell.getValue() === 'Requester') {
sUserNameCell.setValue(userNameCell)
};
}
}
Firstly this defines the columns that you are working with, which are the "Username"(in the scriptuserNameColumn), the column with the "Submitter type"(in the scriptsubTypeColumn) and the column where the username is saved (in the scriptsUserNameColumn). Each have been assigned a number corresponding to a columns in spreadsheet, wher 2 is B, 3 is C, and so on. You can change them to your needs.
Then we create a function called saveUserName() inside this function we get the current spreadsheet, we define what range in the spreadsheet we will work with, here it is everything, then we get the number of rows that has data in them.
After that we go through the data we defined, and setup some variables we can use for each cell. Then we create our if statement, which states, if the "Saved-User-Name-Cell" is empty and the "Submitter-Type-Cell" = the word 'Requester' then we grab the "Saved-User-Name-Cell" and set it's value equal to what is within the "User-Name-Cell".
That's it!

Related

Google Sheets Apps Script - How to add an Arrayformula and multiple associated IF functions within a script (Without showing the formula within UI)

I was wondering if someone is able to assist?
I'm trying to add an Arrayformula consisting of two IF functions, so I'm wanting to merge the following two formulas into one cell:
=ARRAYFORMULA(IF(D13:D104="","",(IF(K13:K104,K13:K104*20,"$0"))))
=ARRAYFORMULA(IF(D105:D="","",(IF(K105:K,K105:K*C4,"$0"))))
So the first section of the sheet needs to be multiplied by 20, and then the figure has changed and needs to be multiplied by 25 (which is cell C4)
Is it possible to merge these into one cell containing an Arrayformula+the two IF functions (or is there another/easier way for this)
Is it possible to add this into Google Apps Script so that it works in the backend (so not just a script that applies the formula into a cell - but doesn't show in the frontend or sheet)
More of a general question - When using Arrayformula with IF; and for example the output is specific text e.g. "Test Complete" associated to the range F2:F (checking if E2:E contains a particular phrase e.g. "Done") - for the empty cells in between (due to setting the False outcome as "") is it possible to somehow randomly add data into these blank cells without interrupting the formula? (so I have to option for automated text if the cell to the left states a particular term/word, but still have the option to manually add random data into blank cells)
Any assistance would be greatly appreciated
As for 1st and 2nd questions: it looks like a task for a custom function. Something like this:
function MULTI() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var value = sheet.getRange('K'+row).getValue();
return (row < 105) ? value * 20 : value * 25;
}
It gets a value from column K and multiplies it by 20 if the row less than 105 and by 25 for the rest of rows.
Here is the variant of the same formula that uses the cell 'C4':
function MULTIC4() {
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getActiveCell();
var row = cell.getRow();
var value = sheet.getRange('K'+row).getValue();
var c4 = sheet.getRange('C4').getValue();
return (row < 105) ? value * 20 : value * c4;
}
And it can be done with the trigger onEdit():
function onEdit(e) {
var col = e.range.columnStart;
if (col != 11) return; // 11 = K
var sheet = e.source.getActiveSheet();
if (sheet.getName() != 'Sheet1') return;
var c4 = sheet.getRange('C4').getValue();
var row = e.range.rowStart;
var dest_cell = sheet.getRange('D'+row);
var value = sheet.getRange(row,col).getValue();
var result = (row < 105) ? value * 20 : value * c4;
dest_cell.setValue(result);
}
It recalculates automatically the value in the cell of column 'D' (current row) every time when you're changing value in the cell of column 'K'. On the sheet 'Sheet1'.

Extract the digits and append it in a different cell?

I am trying to automatically RegExp(extract) the digits(AREA number) in Column 3 combined with the Text 'A' to append in Column 1 Date INDEX.
The problem is I'm not yet familiar in using google sheets app-scripts.
Tried looking for solutions with similar situation as me, but to no avail.
I don't know to put VBA to app-scripts.
Tried using some codes.
I still can't seem to make it work.
Can anyone point me in the right direction?
Thank you if you can help me out. Thanks.
EDIT:
The scenarios is in the office i cant make column for the formula.
It must be "behind the scene".
My googlesheets
//NOT WORKING code
function onEdit(e) {
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var regExp = new RegExp("\d*"); // Extract the digits
var dataIndex = regExp.exec(area)[1];
if(rg.columnStart==3) { // Observe column 3
var vA=rg.getValues();
for(var i=0;i<vA.length;i++){
if(vA[i][0]) {
sh.getRange(rg.rowStart + i,1).appendText((dataIndex) +'A'); // append to column 1 with 'A' and extracted digits
}
}
}
}
This answer extends your approach of using a script with an OnEdit trigger. But there are a number of differences between the two sets of code.
The most significant difference is that I have used the Javascript split method (var fields = value.split(' ');) to get distinct values from the data entry.
Most of the other differences are error checking:
if(rg.columnStart === 3 && area === "work") {: test for sheet="work" as well as an edit on Column C
var value = e.value.toUpperCase();: anticipate that the test might be in lower case.
if (fields.length !=2){: test that there are two elements in the data entry.
if (fields[0] != "AREA"){: test that the first elment of the entry is the word 'area'
if (num !=0 && numtype ==="number"){; test that the second element is a number, and that it is NOT zero.
if (colA.length !=0){: test that Column A is not empty
var newColA = colA+"A"+num;: construct the new value for Column A by using unary operator '+'.
function onEdit(e){
// so5911459101
// test for edit in column C and sheet = work
var ss = SpreadsheetApp.getActiveSpreadsheet;
// get Event Objects
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var row = rg.getRow();
// test if the edit is in Column C of sheet = work
if(rg.columnStart === 3 && area === "work") { // Observe column 3 and sheet = work
//Logger.log("DEBUG: the edit is in Column C of 'Work'")
// get the edited value
var value = e.value.toUpperCase();
//Logger.log("DEBUG: the value = "+value+", length = "+value.length+", uppercase = "+value.toUpperCase());
// use Javascript split on the value
var fields = value.split(' ');
//Logger.log(fields);//DEBUG
// Logger.log("DEBUG: number of fields = "+fields.length)
// test if there are two fields in the value
if (fields.length !=2){
// Logger.log("DEBUG: the value doesn't have two fields")
}
else{
// Logger.log("DEBUG: the value has two fields")
// test if the first field = 'AREA'
if (fields[0] != "AREA"){
// Logger.log("DEBUG: do nothing because the value doesn't include area")
}
else{
// Logger.log("DEBUG: do something because the value does include area")
// get the second field - it should be a value
var num = fields[1];
num =+num
var numtype = typeof num;
// Logger.log("DEBUG: num= "+num+" type = "+numtype); //number
// test type of second field
if (num !=0 && numtype ==="number"){
// Logger.log("DEBUG: the second field IS a number")
// get the range for the cell in Column A
var colARange = sh.getRange(row,1);
// Logger.log("DEBUG: the ColA range = "+colARange.getA1Notation());
// get the value of Column A
var colA = colARange.getValue();
// Logger.log("DEBUG: Col A = "+colA+", length = "+colA.length);
// test if Column A is empty
if (colA.length !=0){
var newColA = colA+"A"+num;
// Logger.log("DEBUG: the new cola = "+newColA);
// update the value in Column A
colARange.setValue(newColA);
}
else{
// Logger.log("DEBUG: do nothing because column A is empty")
}
}
else{
// Logger.log("DEBUG: the second field isn't a number")
}
}
}
}
else{
//Logger.log("DEBUG: the edit is NOT in Column C of 'Work'")
}
}
REVISION
If the value in Column C is sourced from data validation, then no need for and testing except that the edit was in Column C and the sheet = "work".
Included two additional lines of code:
var colAfields = colA.split('-');
var colAdate = colAfields[0];
This has the effect of excluding any existing characters after the hyphen, and re-establishing the hyphen, row number plus "A" and the AREA numeral.
function onEdit(e){
// so5911459101 revised
// only one test - check for ColumnC and sheet="work"
// test for edit in column C and sheet = work
var ss = SpreadsheetApp.getActiveSpreadsheet;
// get Event Objects
var rg=e.range;
var sh=e.range.getSheet();
var area=sh.getName();
var row = rg.getRow();
// test if the edit is in Column C of sheet = work
if(rg.columnStart === 3 && area === "work") { // Observe column 3 and sheet = work
Logger.log("DEBUG: the edit is in Column C of 'Work'")
// get the edited value
var value = e.value
//Logger.log("DEBUG: the value = "+value+", length = "+value.length);
// use Javascript split on the value
var fields = value.split(' ');
//Logger.log(fields);//DEBUG
// get the second field - it should be a value
var num = fields[1];
// get the range for the cell in Column A
var colARange = sh.getRange(row,1);
// Logger.log("DEBUG: the ColA range = "+colARange.getA1Notation());
// get the value of Column A
var colA = colARange.getValue();
// Logger.log("DEBUG: Col A = "+colA+", length = "+colA.length);
// use Javascript split on Column A in case of existing value
var colAfields = colA.split('-');
var colAdate = colAfields[0];
// build new value
var newColA = colAdate+"-"+row+"A"+num;
// Logger.log("DEBUG: the new cola = "+newColA);
// update the value in Column A
colARange.setValue(newColA);
}
else{
Logger.log("DEBUG: the edit is NOT in Column C of 'Work'")
}
}

Is there a way to check over a column range for a certain data?

I have 2 workbooks,
Spreadsheet A has multiple sheets of the same form.
Spreadsheet B records contain cells from Spreadsheet A sheets into a single row per sheet (log).
The first column in Spreadsheet B contains hyperlinks of all sheets in Spreadsheet A. I need to check the hyperlinks column in Spread B as follows:
if hyperlink exist in column A,
check for the next sheet in Spreadsheet A index++
else
record the new data in a row after the last row,,,,
my code used to have clear() function to start submission from scratch to Spreadsheet B, but it's not efficient, execution time wise.
I am trying to manipulate my current code to check manually on existing records and i++/submit new row based on this logic.
you can ignore all missing lines of code because i have it working, i just need the logic of the idea of doing this, since I am not advanced in Apps Script. Thanks in advance for your help.
Spreadsheet A - Sheet1
Spreadsheet A - Sheet2
Spreadsheet B
I want the if statement to run on the Sheet link column in Workbook B.... in case of adding Sheet #3 to Workbook A (picture 1&2), upon submission, I want to check on Sheet links in Workbook B log (because it's unique) if it exists, i++.... if doesn't exist, add 3rd record in log.
for(var index = 2; index < WBA.length; index++)
{
var Sheet = "https://docs.google.com/spreadsheets/d/WBA ID/edit#gid=";
var SID = WBA[index].getSheetId();
var SheetID = Sheet + SID;
var Data = WBB.getDataRange().getValues();
for(var i = 0; i < Data.length; i++)
{
if(Data[i][1] == SheetID)
i++
else
{
var lastRow = WBB.getLastRow() + 1;
var Sheets_ID = new Array()
Sheets_ID.push( [WBA[index].getSheetId()] )
WBB.getRange(lastRow,1).setFormula('=hyperlink("https://docs.google.com/spreadsheets/d/WBA ID/edit#gid=' + Sheets_ID +'")');
var PN_Source = WBA[index].getRange(6,3,1,1).getValues(); //getRange(row number, column number, number of rows, number of columns)
var SC_Source = WBA[index].getRange(8,3,1,1).getValues();
Try this:
function checkForLink() {
var ssB=SpreadsheetApp.getActive();
var sh1=ssB.getActiveSheet();
var rg1=sh1.getRange(1,1,1,4);
var vA1=rg1.getValues()[0];
var hObj={};
vA1.forEach(function(el,i){if(el){hObj[el]=i;}});
var linkA=sh1.getRange(2,hObj['Sheet Link']+1,sh1.getLastRow(),1).getValues().map(function(r){return r[0];});
var ssA=SpreadsheetApp.openById('SSA ID');
var shts=ssA.getSheets();
shts.forEach(function(sh,i){
var vA=sh.getRange(1,1,2,sh.getLastColumn()).getValues();
var sObj={};
vA[0].forEach(function(e,i){sObj[e]=i;});
var shlink=Utilities.formatString('https://docs.google.com/spreadsheets/d/%s//edit#gid=%s',ssA.getId(),sh.getSheetId());
if(linkA.indexOf(shlink)==-1) {
sh1.appendRow([vA[1][sObj.date],vA[1][sObj.age],vA[1][sObj.name],shlink]);
}
});
}

Coldfusion dynamic column names to pass into a function

A user can supply answers for up to 5 question, and each question has 3 columns in the database:
st_m1_id
st_m1_fam
st_m1_cip
st_m2_id
st_m2_fam
st_m2_cip
etc
When the form is submitted I get the IDs into an array and then loop over that and then query a different table to look up fam and cip.
aidms = listToArray(form['idms[]']);
for( i=1;i<=arrayLen(aidms);i++ ) {
qryData = invoke(dataCFC,'queryData', { smid = aidms[i]});
temp = invoke(userCFC,'updateUser',{
userid = session.userid,
st_m#i#_id = aidms[i],
st_m#i#_fam = qryData.fam,
etc......
});
};
How do I notate the dynamic query column names in the function so that when they are passed to updateUser the correct columns are referenced?

Google Sheets - formula for expense sheet

I need a formula that will help me calculate the $ expense amount for my milage rates.
Here is my sheet https://docs.google.com/spreadsheets/d/1PPFuFWbxWi9iIdtYBJvnSNB1j1cjjQutepF3hnpGoFM/edit?usp=sharing
On the tab that's expenses, I need to check the year of my date in Col A (because different years have different rates), then check Col D to see if it says Milage, then check Col E for what type of milage (there are 4 types), then return the number input in Col I times the appropriate rate for that year and type of milage. I have a table set up with the rates in another tab.
I'm thinking it will be a long IF and AND formula. Any help would be great!
In 'Essentials Log', I've changed the format of your year start-end dates to state the year you're referencing. I've added a column for "Milage".
Expense Reference Screenshot
In 'Expenses'!M2, I tried this and it seems to work:
=ARRAYFORMULA(iferror(if(isblank(A2:A),"",I2:I*vlookup(D2:D&year(A2:A)&E2:E,query({'Essentials Log'!Y2:Y&'Essentials Log'!Z2:Z&'Essentials Log'!AA2:AA,'Essentials Log'!AB2:AB},"Select *"),2,false))))
Working Example Screenshot
Have a look (I copied your example sheet): Milage expense
I solved this with creating an app script.
I realized I didn't want to use a formula because in my $ col most entries will be keyed in and so I didn't want to copy and paste a formula every time.
Here is the code if anyone might need it. I added it to the menu so the calculation is done with a click.
function expenseMilageCalculation() {
var auditionsSheet = SpreadsheetApp.getActiveSpreadsheet();
var expensesTab = auditionsSheet.getActiveSheet();
var activeCell = expensesTab.getActiveCell();
var activeRow = activeCell.getRow();
var expenseDate = expensesTab.getRange(activeRow, 1).getValue();
var expenseYear = expenseDate.getFullYear();
var expenseType = expensesTab.getRange(activeRow, 4).getValue();
var expenseDetails = expensesTab.getRange(activeRow, 5).getValue();
var numMiles = expensesTab.getRange(activeRow, 9).getValue();
var essentialsLogTab = auditionsSheet.getSheetByName("Essentials Log")
//2018 Business Milage
if (expenseYear == 2018 && expenseType == "Milage" && expenseDetails == "Business") {
var milageBusinessRate2018 = essentialsLogTab.getRange(3, 27).getValue();
var dollarMilesDeduction = numMiles * milageBusinessRate2018
expensesTab.getRange(activeRow, 8).setValue(dollarMilesDeduction)
}
//2019 Business Milage
if (expenseYear == 2019 && expenseType == "Milage" && expenseDetails == "Business") {
var milageBusinessRate2019 = essentialsLogTab.getRange(8, 27).getValue();
var dollarMilesDeduction = numMiles * milageBusinessRate2019
expensesTab.getRange(activeRow, 8).setValue(dollarMilesDeduction)
}