Running a formula in the background of a cell on Sheets - google-apps-script

I am trying to make a sheet where I can type a time (duration) into a cell without colons or decimals and it show up in the same cell with the colons and decimals (example: input "10342" and the cell reads "1:03.42"). The formula I have that works in another cell is:
=ARRAYFORMULA(TEXT(AVERAGE(VALUE(IF(D3<>"", TEXT(
IF(IFERROR( LEFT(D3, LEN(D3)-6))="", 0, LEFT(D3, LEN(D3)-6))&":"&
IF(IFERROR(RIGHT(LEFT(D3, LEN(D3)-4), 2))="", "00", RIGHT(LEFT(D3, LEN(D3)-4), 2))&":"&
IF(IFERROR(RIGHT(LEFT(D3, LEN(D3)-2), 2))="", "00", RIGHT(LEFT(D3, LEN(D3)-2), 2))&"."&
IF(LEN(D3)>1, RIGHT(D3, 2), "0"&D3), "[h]:mm:ss.00"), ))), "[h]:mm:ss.00"))
I have tried conditional formatting and I'm not the greatest with macros. Is there anyway that this would be possible?

You clearly need an onEdit function. You have to open the script editor within your spreadsheet file and copy paste the code snippet I provide here. With the following code, every time you edit a cell in column A of "Sheet1" you get back the desired format of your input to the exact same cell. If the value you enter is: 10342 it will become: 1:03.42 . If the value you enter is 130342 you get back 13:03.42 . If you want to edit cells only after row 1 (in case you have a header) you can add in the if condition statement the condition : row >1.
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
if (col === 1 && e.source.getActiveSheet().getName() === "Sheet1"){
var valu = e.source.getActiveSheet().getRange(row,1).getValue().toString()
if (valu.length == 5){
var result = valu.slice(0,1)+":"+valu.slice(1,3)+"."+valu.slice(-2);
}
else if ( valu.length==6) {
var result = valu.slice(0,2)+":"+valu.slice(2,4)+"."+valu.slice(-2);
}
e.source.getActiveSheet().getRange(row,1).setValue(result);
}
}
Don't forget to modify the name of the sheet (in my case "Sheet1") as well as the column you want to work with. As you can see my solution uses col===1, e.source.getActiveSheet().getRange(row,1).setValue(result) and var valu = e.source.getActiveSheet().getRange(row,1).getValue().toString(). Number 1 corresponds to column A. If you want to work with column D, for example, you need to replace 1 with 4 for all these formulas. Let me know in the comments if you have any questions.

Related

Google Sheets - Script to Change Currency Formatting Based On Dropdown Selection ($ + €)

I have a Sheet with two tabs — Tab 1 is a quote/invoice and Tab 2 is a list of clients. C3 on Tab 1 contains a dropdown list which pulls from Tab 2, Clients 1-4 use USD ($) but Client 5 uses EURO (€). Tab 1 also contains a costs column in I and a feeder column in H.
My goal is to use a script to change the currency formatting in column I based on what's selected in C3. When Client 5 is selected all costs in I need to contain a '€' prefix, and when anyone else is selected they need to contain a '$' prefix.
In the following code 'H' is a feeder cell where 'EURO' or 'literally anything else' can be entered to change the currency format in 'I' between '€' to '$':
function onEdit(e){
var sheetName = "Main Sheet";
var currencyCol = 8; //column H
var amountCol = 9; //column I
var defaultFormat = "[$$]#,##0.00";
var currencyFormat = {"USD":"[$$]#,##0.00",
"EURO":"[$€]#,##0.00"};
var r = e.range;
if(e.source.getSheetName()==sheetName && r.getColumn() == currencyCol){ // This assumes I want to manually change H, I'd rather have it automatically change between EURO (including € in column I) when client 5 is selected, and USD (including $ in column I) when clients 1-4 are selected
var uf = currencyFormat[r.getValue()];
uf = uf?uf:defaultFormat;
r.offset(0,amountCol-currencyCol).setNumberFormat(uf);
}
}
It works, but I have to manually type 'EURO' or 'anything else' in 'H' line-by-line to change the currencies for 'I' - but I need it to change automatically based on the selection in C3.
I tried using =if(C3="Client 5", "EURO", "") in Column H which works the first time Client 5 is selected in the dropdown, but doesn't reset 'I' to '$' once changed and needs to be manually typed in before working again.
I also tried 2 Macros which manually input 'EURO' and 'USD' into column H and tried to run them with a script to trigger when Client 5 is selected. It worked in 'H', but 'I' didn't change when the words appeared I think the issue is that the code isn't/can't trigger outside of manual data entry.
Any help would be great, I'm a beginner and I can't wrap my head around it. Feel free to message me or ask for a link to a test sheet.
Also I attached a screenshot of what tab 1 & 2 look like. I manually changed EURO to USD on Tab 1 to set that currency in column I, ideally that change can be based off C3Spreadsheet example
I believe your goal is as follows.
When a dropdown list of "C3" of "Tab1" sheet is changed, you want to change the number format of the cells "I8:I".
You want to retrieve the values of the dropdown list and the corresponding number formats from the cells "B4:C8" of "Tab2".
In this case, how about the following modification?
Modified script:
function onEdit(e) {
var sheetName1 = "Tab1"; // Please set the sheet name of "Tab1".
var sheetName2 = "Tab2"; // Please set the sheet name of "Tab2".
var r = e.range;
if (e.source.getSheetName() == sheetName1 && r.getA1Notation() == "C3") {
var defaultFormat = "[$$]#,##0.00";
var currencyFormat = { "DOLLAR": "[$$]#,##0.00", "EURO": "[$€]#,##0.00" };
var obj = e.source.getSheetByName(sheetName2).getRange("B2:C8").getValues().reduce((o, [b, c]) => (o[b] = c, o), {});
var sheet = r.getSheet();
sheet.getRange("I8:I" + sheet.getLastRow()).setNumberFormat(currencyFormat[obj[e.value]] || defaultFormat);
}
}
Note:
In this modified script, when the dropdown list of "C3" of "Tab1" sheet is changed, the number format of cells "I8:I" is changed by the values of "B4:C8" of "Tab2". In this case, the column "H" is not used. Please be careful about this.
In your script, "USD":"[$$]#,##0.00" and "EURO":"[$€]#,##0.00" are used. But, in your image, "DOLLAR" and "EURO" are used. In this modification, "DOLLAR" and "EURO" are used. Please be careful about this.
Reference:
reduce()

Google Sheet Macro - how do I return a column number based on dynamic cell contents?

I have the following code as a starting point. I want to select the entire column where row 3 contains a specific date value (it will be the date of the previous Monday; I have a formula returning this date in cell E1).
function selectDate() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
ss.getRange(3,?,1,ss.getMaxColumns()).activate();
}
Basically, the getRange column value would be interpreted as something like: "Find the column number where the value in row 3 is equal to the value in cell E1".
Any ideas would be very helpful, even if it's using a totally different method to achieve the same thing. Thank you so much!
In your situation, how about the following sample script?
Sample script:
function selectDate() {
var sheet = SpreadsheetApp.getActiveSheet();
var searchValue = sheet.getRange("E1").getDisplayValue();
var res = sheet.getRange(3, 1, 1, sheet.getLastColumn()).createTextFinder(searchValue).matchEntireCell(true).findNext();
if (!res) return;
var column = res.getColumn();
sheet.getRange(1, column, sheet.getLastRow()).activate(); // Here, the found column is activated.
Browser.msgBox("Found column number is " + column); // Here, the found column number is shown in a dialog.
}
From your situation, I thought that getRange(3,?,1,ss.getMaxColumns()) in your script might be getRange(3, 1, 1, sheet.getLastColumn()).
When this script is run, row 3 is searched using the value of cell "E1". When the value is found, as a sample, the found column is activated and the column number is shown in a dialog. This is a sample. Please modify this for your actual situation.
Note:
If no column is selected, it is considered that the value of cell "E1" is not found in row 3. At that time, can you provide the detail of your Spreadsheet? By this, I would like to modify it.
Reference:
createTextFinder(findText) of Class Range

How to select cells with the same value in a column and change them to a different value?

I need some help with the Google Sheets Apps Script to do the following:
select column T
apply filter and select only values "In review" in that column
change all values "In review" to "Done"
select and copy rows with "Done" value from columns A-L and N-R (i.e. skip column M).
I have tried recording a macro (with relative and absolute values) but it only works for the specific rows that were selected for the macro. It does not apply to the entire sheet.
function myFunction() {
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
const lastRow = spreadSheet.getLastRow();
var arrayDoneRowNumber = []
for (let i = lastRow; i > 1 ; i--) {
var value = spreadSheet.getRange('T'+i).getValue();
if (value == 'InReview') {
spreadSheet.getRange("T"+i).setValue("Done");
arrayDoneRowNumber.push(i)
} else if (value == 'Done') {
arrayDoneRowNumber.push(i)
}
}
console.log(arrayDoneRowNumber)
}
This code snippet is responsible for the 1st three tasks you have mentioned. I will update the code when you have responded to my question for the 4th task.
Note :- Anyhow the array arrayDoneRowNumber has the row numbers of all the rows which have Done in column T. You can simply process further using this information of row numbers itself.

Automatically populate cell in Google Sheets when another cell in same row is manually filled but error

In Google Sheets, I want to create a macro that will automatically populate a column in each row when another column in that row is manually filled. The autofilled cell will use a formula that import from other googlesheet file and using query to import the data. I currently using script but i cant put a apostrof to complete my formula
`
function onEdit(e) { //Runs every time the sheet is edited
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('DB Mitra'); //Change this to whatever your sheet is named
var inputCol = sheet.getRange('B2'); //Change this to whatever column the date is going to be entered
//This is the range that will be checked. Slightly redundant, but makes it easier to reuse this script without needing to retype every variable
var myRange = inputCol;
//Get the row & column indexes of the active cell
var row = e.range.getRow();
var col = e.range.getColumn();
//Check that your edited cell is within the correct column
if (col == myRange.getColumn()) { //This runs only if a value is entered into the column defined in 'inputCol'
if(sheet.getRange(e.range.getA1Notation()).getValue() == '') {return}; //If the edited cell is empty (ie the date is deleted, nothing happens)
if(row == 1) {return} //If the header is changed, nothing happens
let codeCell = sheet.getRange('D'+row); //Change to the column that will store the generated code value
codeCell.setValue('=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B'+row+'&"'")');
//let hardValue = codeCell.getValue(); //Gets the value from the formula you just entered
//codeCell.setValue(hardValue); //Replaces the formula with just the resulting value
};
}
`
the formula should be like this
enter image description here
but it always error if i put it like that
enter image description here
Thank you for anyone willing to help me. credit to Automatically populate cell in Google Sheets when another cell in same row is manually filled for the inspiration code
In your script, how about modifying using the template literals as follows?
From:
codeCell.setValue('=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B'+row+'&"'")');
To:
codeCell.setValue(`=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B${row}&"'")`);
or
codeCell.setFormula(`=QUERY({IMPORTRANGE("1-K_ZltvOev2t9iqKIOHR8B-PY6ODBKYAwTjaDzLbHJE";"2022!B2:T494")};"SELECT Col4 WHERE Col1 = '"&B${row}&"'")`);
Reference:
Template literals

Google Apps Script - How to get clipboard column number

Goal: When a user pastes a value to a cell, I want the script to check whether or not the copied value is from the same column or not.
Problem: Oftentimes, the user copies a cell from a different column and pastes in a cell that's under another column. This causes some problems for this particular sheet, so I want to be able to have the script check if the clipboard’s copied value's column number (or letter) is the same with the column of where the user is trying to paste it.
Example:
Scenario A: User copied a cell from A1 and attempts to paste it to B2 (either by mistake or intentionally)
If statement check: Check if the user’s clipboard copied value’s column number (or letter) is equal to 2 (if by letter: B).
Result: Since the copied column number is 1 and editing column number is 2, the script will show an error message to refuse the editing.
Scenario B: User copied a cell from A1 and attempts to paste it to A2
If statement check: Check if the user’s clipboard copied value’s column number (or letter) is equal to 1 (if by letter: A).
Result: Since the copied column number is 1 and editing column number is also 1, the script will allow the user to pates the value to A2.
Here's my attempt: I thought it would make sense to use the onEdit function to compare
function onEdit(e) {
const range = e.range;
const source = e.source;
const sheetName = source.getActiveSheet().getName();
const row = range.getRow();
const column = range.getColumn();
const editedRangeValue = range.getValue();
// Call the copyPrevention function
copyPrevention(sheetName, range, row, column, editedRangeValue);
}
function copyPrevention(sheetName, range, row, column, editedRangeValue) {
const headerRowNum = 12;
if (sheetName == 'Status' && row > headerRowNum && editedRangeValue != '') {
// row variable: This is to ensure the editing will only apply if the user tries to edit after row 12 (headerRow).
if (column == "") { // The "" is just a placeholder. If this is even possible, I would like to compare user's editing column number & their clipboard column number. And if the column numbers are the same, then I'd like the script to continue the execution without throwing any errors.
range.setValue(editedRangeValue);
} else if (column != "") { // The "" is just a placeholder. I would like to compare user's editing column number & their clipboard column number. And if the column numbers are not the same, then I'd like the script to throw an error and not let the user edit the cell.
const statusSheetUi = SpreadsheetApp.getUi();
statusSheetUi.alert("You're pasting in the wrong column!");
}
}
}
I have a feeling that this isn't possible, however wanted to check.
Thank you!