Currency format in google apps script - google-apps-script

I have created some set of rows for a requirement gathering document in which for a range I have set numberformat for USD as
ex_range.setNumberFormat("[$$]#");
upon execution, in the range when the user enters the value, the formatting rounds it to a whole number.
I tried
ex_range.setNumberFormat("[$$]#,##0.0000");
and for the above, when the user enters a value say e.g. 34.56 I get $34.5600
I want the user to enter the value and whatever decimal points they enter to not round off or add extra zeros.
If the user enters 50.67, I should get $50.67 and if 45.5670 is entered I should get $45.5670
Please help in how to set the format to USD for the range and no round up happens to the values.
I am having the user fill value in the range K43:P57, they should be able to enter any value with any decimal number, the value should not get rounded off.
and the script should read the range K43:P57and identify the value with highest decimal numbers and populate in G43

With an onEdit(e) function you can set the number format for the edited cell. This will override the column formatting. Be aware that the 0 at the end of 5.989830 will be "cut off" before sending it to the script. So the value of n inside the script below will be 5.98983 like #Tanaike is mentioning in the comments. Nevertheless i hope this will help:
EDIT: If the original column formatting is Plain text the solution below will work with tailing zero's
Extensions -> Apps script.
Paste the code.
Change the sheetname and column number to the values where theformatting needs to happen.
Save an quit.
Test it out.
function onEdit(e) {
//Settings
const sheetname = "BB";
//Rest of script
const sheet = e.source.getActiveSheet();
const range = e.range;
const n = e.value;
if (isNaN(n)) return;
if (sheet.getName() !== sheetname) return;
const column = range.getColumn();
if (column < 11) return;
if (column > 16) return;
const row = range.getRow();
if (row < 43) return;
if (row > 57) return;
const length = n.toString().split(".")[1].length;
const zeros = new Array(length).fill("0").join("");
const format = "#,##0." + zeros;
range.setNumberFormat(format);
}

Related

Replace text with hyperlinked version onEdit

I have a google sheet with a list of people's initials in range A4:A.
These initials are each hyperlinked to a different part of my sheet.
Column MM contains many cells that all have a data validation dropdown list referencing the initials list in A4:A
I need a script that triggers on edit so that when a user selects initials in the dropdown list in column MM, the script replaces it with the hyperlinked version from column A
My scripting knowledge is rudimentary. Normally I'd do a replace something like the below but I'm not sure how to implement the search so it takes the value from column MM and searches for it in columnA (or even if this would take the hyperlink function along with it.
`function replaceText(){
var oldText = "AB";
var newText = "AB hyperlinked";
var sheet = SpreadsheetApp.getActive().getSheetByName('SHOTS');
sheet.getRange("MM1:MM" + sheet.getLastRow()).createTextFinder(oldText).replaceAllWith(newText);
}`
Thanks in advance for any help given
If you have the chance of having an additional column, you can do a workaround without script with FILTER:
=FILTER(A2:A,A2:A=MM1)
Or if you want it as an array for many rows
=BYROW (MM1:MM,LAMBDA(each,IF(each="","",FILTER(A2:A,A2:A=each))))
Check in this image how when I chose value "b" it returns the hyperlinked value in the coloured column
OPTION B with SCRIPT:
Please check if MM is column 351, if not change that number. Run it once from the console (it will give an error, but it's just for approving the permissions), then go to your sheet and start trying with your dropdown:
function onEdit(e) {
var ecolumn = e.range.getColumn()
if (ecolumn == 351){
var sheet = SpreadsheetApp.getActive()
var range = sheet.getActiveRange();
var value = range.getValue()
var lookuprange = sheet.getRange("A:A").getValues().map(n => n[0])
var index = lookuprange.indexOf(value)+1
if (index != 0){
var link = sheet.getRange("A"+index).getRichTextValue().getLinkUrl()
var richValue = SpreadsheetApp.newRichTextValue()
.setText(value)
.setLinkUrl(link)
.build();
range.setRichTextValue(richValue);}}
}
REFERENCE: Apps Script: how to get hyperlink from a cell where there is no formula

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

Using cell input into function and ovewriting result into result in same cell in Google Sheet

In Google Sheet, I would like to take the input of a cell, make a calculation, and display the result in the same cell in a different format. This would likely always be a percentage value that I would use conditional formatting to color the cell to provide a 'dashboard' view of statistics.
Example would be usage statistics for a month.
Assets
Records
limit
50
1000
November
29
295
Assets
Records
limit
50
1000
November
58%
30%
I found a Quora post detailing how to create your own scripts, so I believe I have the baseline of taking and modifying content of a cell:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveSelection();
var cell_input = cell.getValue();
var cell_address = cell.getA1Notation()
var cell2 = ss.getRange(cell_address);
cell2.setFormula('=2*'+cell_input)
}
In this example, I'm unsure how to reference the cell it should be dividing against.
Here's a general example that should give you an idea of how to manipulate the cells, formats and values in Sheets:
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveSelection();
var cell_input = cell.getValue();
var divisor = cell.offset(-1, 0)
if (e.range.getA1Notation()=="B3" || "C3"){
cell.setNumberFormat("#").setValue(Math.ceil((cell_input / divisor.getValue()) * 100) + "%")
}
}
If you create a sheet that looks like this you will get the behavior you were looking for in B3 and C3:
How it works:
Add the e parameter to the onEdit(e) trigger so you can use e.range to read the range that called the function.
To get the cell you're dividing against you need to either know its exact range or its relative position to the cell that called it. Since in your sample the percentage cell is below the divisor, you can just offset() it by -1, which returns the cell above it. If the relative position changes you'll need to take this into account to modify the offset but it should work in general if your table has a consistent structure.
You'll need to use an if to fire the trigger only in a specific range, otherwise the entire sheet will be affected. You do this by comparing the caller e.range to your desired range. In this example for the sake of simplicity I just had two cells so I just compared the individual B3 and C3 cells to e.range.getA1Notation(), but if you want a bigger range you'll probably want to use a more advanced technique like the ones in this question
To get around the format problem described in TheWizEd's comment I'm forcing the cell to a text value using setNumberFormat("#"). This way if you enter a value a second time it will read it as a number rather than a percent. I tested using the value elsewhere in the sheet and it still works as a percentage when needed, but watch out for unintended behavior.
Sources:
Simple triggers
Range object documentation
When working with triggers, take advantage of the event object.
Replace
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveSelection();
var cell_input = cell.getValue();
by
function onEdit(e){
var cell_input = e.value ?? 0;
Notes:
SpreasheetApp.Spreadsheet.getActiveSeletion() returns the first range that belongs to the active selection, this might cause problems because the active seleccion could include multiple cells, and the current cell could be any cell in the selection even one cell that is not part of the returned range.
SpreadsheetApp.Range.getValue() returns the value of the top left cell in the range. A user could select multiple cells and use the tab key to change the current cell, so under certain circunstances the value obtained this way might not be the value of the edited cell.
e.value ?? 0 is used to get 0 as the default value, i.e., when a cell is cleared.
As onEdit is triggered when any cell is edited your script should include a condition to only change the corresponding cells.
function onEdit(e){
const cell_input = e.value ?? 0;
if(e.range.rowStart === 3 && [2,3].includes(e.range.columnStart)){
const newValue = (100 * cell_input / e.range.offset(-1,0).getValue()).toFixed() + '%';
e.range.setValue(newValue);
}
}
The above uses
SpreadsheetApp.Range.offset to get the cell above of the edited cell.
Writes a the percentage as string, taking advange of the Google Sheets automatic data type assignation.
References
https://developers.google.com/apps-script/guides/triggers
https://developers.google.com/apps-script/guides/triggers/events

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

Running a formula in the background of a cell on Sheets

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.