Related
Please excuse my limited knowledge in advance.
In Google Sheets, I have a budget column (K) that sums multiple inputs and displays the most recent totals.
I am trying to create a script that will copy select values from column K and set those values into column I upon execution.
Both column K and I have sum totals in various rows throughout so a simple copy and pasting of the entire column would overwrite those functions. This will be a repeatable action to set new values once they are calculated into this column so I plan to assign it to a button.
I'm using User Tanaike's wonderful RangeListApp to help reference the multiple ranges I'm referencing.
The first half of the code seems to be working:
function UpdateEFC() {
var rangeList = ['K4:K6', 'K9:K14', 'K17:K18', 'K21:K24', 'K27', 'K30:K38', 'K41:K49', 'K52:K53', 'K56:K60', 'K63:K67', 'K70:K72', 'K75:K76', 'K79:K85', 'K88:K92', 'K95:K106', 'K109:K114', 'K117:K126', 'K129:K133', 'K136:K147', 'K150:K153', 'K156:K163', 'K166:K167', 'K170:K174', 'K177', 'K180:K182', 'K185', 'K188:K190', 'K193', 'K196:K205', 'K208:K214', 'K217'];
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var r = RangeListApp.getSpreadsheet(spreadsheet).getRangeList(rangeList).getDisplayValues();
Again, each range listed (i.e. "k4:k6") are sum functions in each cell. When I log this script it returns the calculated value in each cell. Here is an example from the log:
[{range='CR Template'!K4:K6, values=[[ $ 28,000.00 ], [ $ 25,000.00 ], [ $ 27,500.00 ]]},
When I attempt to set these values into column I, however, I run into issues.
I have tried the following:
var destinationList = ["I4:I6", "I9:I14", "I17:I18", "I21:I24", "I27", "I30:I38", "I41:I49", "I52:I53", "I56:I60", "I63:I67", "I70:I72", "I75:I76", "I79:I85", "I88:I92", "I95:I106", "I109:I114", "I117:I126", "I129:I133", "I136:I147", "I150:I153", "I156:I163", "I166:I167", "I170:I174", "I177", "I180:I182", "I185", "I188:I190", "I193", "I196:I205", "I208:I214", "I217"];
var values = rangeList;
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
RangeListApp.getSpreadsheet(spreadsheet).getRangeList(destinationList).setValues(values);
This script returns the cell ranges into column as written in the script. i.e. I4 = K4:K6, I5 = K4:K6, I6 = K4:K6 but does not return the displayed numerical summed value.
I have also tried a version where
var values = r;
My thinking was to take the output of displayed values and set those values into the new range list, however this only returned:
[object Object]
into each cell.
I know I have something wrong here in how to define or recall the values so any guidance here would be appreciated.
Many thanks in advance.
I believe your goal is as follows.
You want to copy the values from ['K4:K6', 'K9:K14', 'K17:K18',,,] to ["I4:I6", "I9:I14", "I17:I18",,,].
Issue and workaround:
In the current stage, unfortunately, my RangeListApp cannot copy the values with the ranges. So, in this case, as a current workaround, I would like to propose using a script with Sheets API. The sample script is as follows.
Sample script:
Before you use this script, please enable Sheets API at Advanced Google services.
function myFunction() {
var sheetName = "Sheet1"; // Please set your sheet name.
// These ranges are from your script.
var srcRangeList = ['K4:K6', 'K9:K14', 'K17:K18', 'K21:K24', 'K27', 'K30:K38', 'K41:K49', 'K52:K53', 'K56:K60', 'K63:K67', 'K70:K72', 'K75:K76', 'K79:K85', 'K88:K92', 'K95:K106', 'K109:K114', 'K117:K126', 'K129:K133', 'K136:K147', 'K150:K153', 'K156:K163', 'K166:K167', 'K170:K174', 'K177', 'K180:K182', 'K185', 'K188:K190', 'K193', 'K196:K205', 'K208:K214', 'K217'];
var dstRangeList = ["I4:I6", "I9:I14", "I17:I18", "I21:I24", "I27", "I30:I38", "I41:I49", "I52:I53", "I56:I60", "I63:I67", "I70:I72", "I75:I76", "I79:I85", "I88:I92", "I95:I106", "I109:I114", "I117:I126", "I129:I133", "I136:I147", "I150:I153", "I156:I163", "I166:I167", "I170:I174", "I177", "I180:I182", "I185", "I188:I190", "I193", "I196:I205", "I208:I214", "I217"];
var ssId = SpreadsheetApp.getActiveSpreadsheet().getId();
var values = Sheets.Spreadsheets.Values.batchGet(ssId, { ranges: srcRangeList.map(e => `'${sheetName}'!${e}`), valueRenderOption: "FORMATTED_VALUE" }).valueRanges;
var data = values.map(({ values }, i) => ({ range: `'${sheetName}'!${dstRangeList[i]}`, values }));
Sheets.Spreadsheets.Values.batchUpdate({ data, valueInputOption: "USER_ENTERED" }, ssId);
}
When this script is run, the values of srcRangeList is copied to dstRangeList.
Note:
I would like to consider updating RangeListApp.
References:
Method: spreadsheets.values.batchGet
Method: spreadsheets.values.batchUpdate
I've heavily edited the original question I posted, as i have solved some of the issue myself. I'm now stuck on just one thing.
function payINVOICE() {
var ss = SpreadsheetApp.getActive();
var ds = SpreadsheetApp.openById("14imcEob2qIZbH6AjGYtf16MJxbnfkhQn1ae4jR-Nzq4");
var srcSheet = ss.getSheetByName("INVOICE_ENTRY");
var dstSheet = ds.getSheetByName("INVOICE_ENTRY");
var data_range = srcSheet.getRange('B4:J100');
var data_data = data_range.getValues();
var data_clean = data_data.filter(function (r) {return r[1]});
var clear_range = srcSheet.getRange('B4:I100');
var lr = dstSheet.getLastRow();
dstSheet.getRange(lr+1, 2,data_clean.length,9).setValues(data_clean);
clear_range.clear();
}
This code checks the range B4:J100 for a value in Column B.
If there is a value and the script is run, it copies those rows onto dstSheet.
My role is marking invoices as paid or not.
The dstSheet will already contain the data, which is pulled back into the srcSheet with a query. Column K is not part of the original query.
If I mark a row as "PAID" in column K on the srcSheet, I want the code to take the data_data variable and overwrite what is already in the dstSheet, so that the query then pulls the data back into srcSheet with column J then showing "PAID".
It means I can then change column K to "NOT PAID", run the script again and it will over-write the "PAID".
This makes better sense than my last post and I am so close to achieving what I need, just stuck on this last bit.
If you simply want to monitor the changes between the two mentioned sheets, it would be much easier to use an onEdit(e) trigger which will tell you which cell has been edited.
Snippet
function payINVOICE(e) {
var srcSheet = SpreadsheetApp.getActiveSheet(); //gets the active sheet which is supposed to be source sheet
var dstSheet = SpreadsheetApp.openById('DEST_SHEET_ID').getSheetByName('INVOICE_ENTRY'); //gets the destination sheet
if (e.range.getSheet().getName() == 'INVOICE_ENTRY' && e.range.getColumn() == 11) { //e specifies where the edit has been made - therefore this if condition checks if the edit is in the INVOICE ENTRY sheet and if the column is the K column
var row =e.range.getRow(); //this gathers the row at which the edit has been made
var data = srcSheet.getRange(row, 2, 1, 10).getValues(); //this gathers the data corresponding to the row at which the edit has been made
dstSheet.getRange(row, 2, 1, 10).setValues(data); //this sets the data into the corresponding row in the destination sheet
}
Explanation
The above code uses the onEdit(e) installable trigger and the e event object. In this way, when an edit is being made on the srcSheet on the 11th column (aka K column) and the sheet name is "INVOICE_ENTRY", then the row at which the change has been made is kept in the row variable. Afterwards, the corresponding row of data is kept in the data variable; the getRange(row, 2, 1, 10) references the range for the row at which the change on the K column has been made. In order to update the dstSheet, the data value is set to the according range using setValues(data).
Installing the trigger
To make the payINVOICE(e) function trigger on an edit action, you need to install an onEdit trigger.
This is being done by accessing the project's triggers by clicking this icon:
After that, you just need to create a new trigger by clicking the Add trigger button and create a trigger with the following settings:
Trying the function
In order to try the behavior for this, you just need to make an edit on the srcSheet on the K column and this change will be reflected in the destSheet.
Note
The ranges that have been used in this script are chosen considering the fact that:
K column consists of the PAID/NOT PAID text;
The srcSheet and the dstSheet have the data wanted in the same ranges.
You might need to customize these according to your sheet and add the needed formulas/filters you have mentioned.
Reference
Apps Script Installable Triggers;
Apps Script Event Objects.
I've been trying to build a spreadsheet where a button, once it's been clicked, it would build a new row above a specific cell containing a fixed value/sting.
Practical example would be a sheet containing cells with different values and the script should run through all the cells, find a cell with a specific string and add an empty row above that.
I've been looking around for a similar script to tweak and adapt to my situation but all of my attempts have been unsuccessful so far.
This is what I've got:
function AddRowAbove() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //get the active spreadsheet
var sheet = ss.getActiveSheet(); // get the active sheet
var rangeData = sheet.getDataRange(); //get all the data in the spreadsheet (is that the right way to do this??
// for every data within the range of data variable
for (var i = 0; i< rangeData.length ; i++){
if(rangeData[i] == "TOT") // Check to see if cell has "TOT" as value
{
ss.insertRowsBefore(spreadsheet.getActiveRange().getCell(rawData[i]), 1); // is that the right function to call???
}
}
Though logically this seems to be correct, I'm not used to script with this programming language so it's hard for me to find where the problem is.
Any help would be greatly appreciated.
Also, can anyone point me out to any resource I can study to get the basic of this scripting language??
Thanks!
I have a column with formatted ids (Brazilian CPF).
The user input is 12345678900 and the displayed value is 123.456.789-00.
If I copy and paste this column to another column, the values pasted are in 12345678900 format.
I want to copy the "displayed values" of a column to another column using google script what's the simple code for that?
I am trying using a loop, but my sheet is too big and it is very slow!
Updating cell with the displayed value format is not working.
while (primeira_linha <= ultima_linha){
var cpf_formatado = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2020").getRange(primeira_linha,10).getDisplayValue();
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("2020").getRange(primeira_linha,10).setValue(cpf_formatado);
primeira_linha++;
You want to get values from the column "J" on the sheet of 2020 in the active Spreadsheet using getDisplayValue.
You want to put the retrieved values to the other column as the text.
You want to reduce the process cost of your current script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In your script, getDisplayValue and setValue are used in the loop. By this, the process cost becomes high.
Pattern 1:
In this pattern, in order to reduce the process cost, getDisplayValues and setValues are used without using the loop. So the values are retrieved as the text values, and put them as the text values.
Modified script:
When your script is modified, it becomes as follows. Before you run the script, please set the variables.
var primeira_linha = ##; // Please set the start row.
var ultima_linha = ##; // Please set the end row.
var sourceColumn = 10; // Source column. In this case, it's the column "J".
var destinationColumn = 10; // Please set the column you want to put the values. In this case, it's the column "J".
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("2020");
var values = sheet.getRange(primeira_linha, sourceColumn, ultima_linha - primeira_linha + 1).getDisplayValues();
sheet.getRange(primeira_linha, destinationColumn, values.length, 1).setNumberFormat("#").setValues(values);
From your script, it seems that the values retrieved with getDisplayValues from the column "J" are put to the same column. So the above modified script is the same process.
And in this case, in order to modify the cell format, I used setNumberFormat("#"). In this case, the values are put as the text. If you don't want to modify the cell format. Please remove .setNumberFormat("#").
Pattern 2:
In this pattern, copyTo is used. In this case, the values are copied with the cell format.
Modified script:
var primeira_linha = ##; // Please set the start row.
var ultima_linha = ##; // Please set the end row.
var sourceColumn = 10; // Source column. In this case, it's the column "J".
var destinationColumn = 10; // Please set the column you want to put the values. In this case, it's the column "J".
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("2020");
var sourceRange = sheet.getRange(primeira_linha, sourceColumn, ultima_linha - primeira_linha + 1);
var destinationRange = sheet.getRange(primeira_linha, destinationColumn);
sourceRange.copyTo(destinationRange);
References:
getDisplayValues()
setValues()
setNumberFormat()
copyTo(destination)
If I misunderstood your question and this was not the direction you want, I apologize.
I have been searching through question and example everywhere but I can not seem to find an answer. I need to set these formulas in the header row and columns AQ:1 to AV:1(AQ1:AV1).
["={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}",
"={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}",
"={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}",
"={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}",
"={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}"],
and I need to put this into the second row of column AQ (AQ2).
["=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
I keep getting this error message and I cannot save the script.
Missing ] after element list. (line 138, file "Code")
I think I know why but I need the headers to be titled with the correct text because I use the headers in other functions.
function setFormulas(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This sets the formulas to be a row of sums, followed by a row of averages right below.
// The size of the two-dimensional array must match the size of the range.
var formulas = [
["={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}",
"={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}",
"={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}",
"={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}",
"={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}",
"={"Wages:";ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
["=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}"],
];
var cell = sheet.getRange("AQ1:AW2");
cell.setFormulas(formulas);
}
Am I missing something or am I doing it completely wrong and need to find another way to do it. I also need to add the formulas to every sheet in the spreadsheet but I have not been able to test if it works. Thank you in advance for any help.
UPD:
It seems like double quotes are interfering here. To avoid this, you can use single quotes for formula enclosure and double quotes within formula, like this:
'={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}'
As mentioned in comments:
Arrays would expand so you are likely to need setting formulas in one row, like AQ1:AW1
Besides, if there's source data in columns AQ:AU (by the looks of formulas), setting array formulas in the same columns will most likely return error: Array result was not expanded because it would overwrite data in AQ18.
You seem to have an extra } at the end of the last formula
Try this and adjust to your needs:
function setFormulas(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This sets the formulas to be a row of sums, followed by a row of averages right below.
// The size of the two-dimensional array must match the size of the range.
var formulas = [
['={"Hours:";ArrayFormula((IF(LEN(AE2:AE),((AF2:AF-AE2:AE)*24)+(((T2:T-S2:S)*24))+(((I2:I-H2:H)*24)),)))}',
'={"Rest Hours:";ArrayFormula((IF(LEN(AE2:AE),((M2:M)*24)+(((X2:X)*24))+(((AJ2:AJ)*24)),)))}',
'={"Rest Hours Wages:";ArrayFormula((IF(LEN(AE2:AE),(AI2:AI*(AJ2:AJ*24)+(L2:L*(M2:M*24)+(W2:W*(X2:X*24)))),)))}',
'={"Hours-RestHours:";ArrayFormula((IF(LEN(AE2:AE),((AQ2:AQ-AR2:AR)),)))}',
'={"Rate:";ArrayFormula((IF(LEN(AE2:AE),((E2:E+P2:P+AB2:AB)),)))}',
'={"Wages:";ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))}',
'=ArrayFormula((IF(LEN(AE2:AE),((AT2:AT*AU2:AU)+AS2:AS),)))']
];
var cell = sheet.getRange("AW1:BC1");
cell.setFormulas(formulas);
}