apps script getValue contents only - google-apps-script

I have the following that works fine:
function phototable() {
var ss = SpreadsheetApp.openById('####');
var lastRow = ss.getLastRow();
ss.getRange('H'+lastRow)
.setValue('=VLOOKUP("Form Responses_Images/"&B'+lastRow+',importrange("https://docs.google.com/spreadsheets/d/####/edit","Form Responses!U:Z"),4,false)');
}
However, I don't want the formula copied into column H, just the actual value. So I tried:
ss.getRange('H'+lastRow)
.getValue('=VLOOKUP("Form Responses_Images/"&B'+lastRow+',importrange("https://docs.google.com/spreadsheets/d/###/edit","Form Responses!U:Z"),4,false)')
.copyTo('H'+lastRow,{contentsOnly:true});
But that doesn't insert anything into column H. Any ideas?

Modification points:
About I have the following that works fine:, when I saw the above script, I think that an error occurs at getValue. Because getValue has no arguments. I thought that getValue was setValue.
At copyTo('H'+lastRow,{contentsOnly:true}), the 1st argument is thr range object.
In order to copy the result of the formula during the script as the string, it is required to use flush.
When above points are reflected to your script, it becomes as follows.
Modified script:
function phototable() {
var ss = SpreadsheetApp.openById('####');
var lastRow = ss.getLastRow();
var range = ss.getRange('H'+lastRow);
range.setValue('=VLOOKUP("Form Responses_Images/"&B'+lastRow+',importrange("https://docs.google.com/spreadsheets/d/###/edit","Form Responses!U:Z"),4,false)');
SpreadsheetApp.flush();
range.copyTo(range, {contentsOnly:true});
}
Note:
In your script, ss is the 1st tab of the Spreadsheet. Please be careful this.
References:
flush()
copyTo(destination, options)

Issues / Explanation:
You have 2 ways to update the cell in column H with the value of the formula:
If you want to update the cell in H with its value then get the value and set it back:
range.setValue(range.getValue());
Use the copyTo() method:
range.copyTo(range, {contentsOnly:true});
As a bonus information, copyTo() can not be used if the source range and the target range are not of the same spreadsheet file.
Since this process happens really fast, it is a good idea to use flush() for the pending sheet changes to be completed.
Solution:
function phototable() {
var ss = SpreadsheetApp.openById('####').getSheetByName('Sheet1');
var lastRow = ss.getLastRow();
var range = ss.getRange('H'+lastRow);
range.setValue('=VLOOKUP("Form Responses_Images/"&B'+lastRow+',importrange("https://docs.google.com/spreadsheets/d/####/edit","Form Responses!U:Z"),4,false)');
SpreadsheetApp.flush();
range.setValue(range.getValue());
// range.copyTo(range, {contentsOnly:true}); // choose this or the previous line
}
Modify Sheet1 to the name of the sheet you want to apply this operation.
Also it is a better practice to choose a particular sheet before you apply any function to it. To get a sheet by its name use getSheetByName().

Related

How to use copyTo() without showing "destination" tab/sheet, keeping the user where he is (using Google Apps Script)?

there!
The functions below basically copies rows into another sheet. This is a tweaked sample of the code.
The issue I'm finding is:
When this copies the row(s) into the new sheet, that sheet becomes active. I'll delete it later, but the user gets dragged into this temporary sheet and I'd lie to know if there'd be a way to do it using copyTo() but without shifting tabs in front of the user.
/*
*It moves the order row into Production Sheet in WIP, as the user sets status Confirmed;
*/
function installedOnEdit(e) {
const dstSpreadsheetId = "XXXXXxxxxxxxxXXXXXXXXXX" // Please set the destination Spreadsheet ID.
const destSheetName = 'Página23'
//Maps the values to serve as criteria to decide if this should continue running
const ss = SpreadsheetApp.getActiveSpreadsheet();
const orderSheet = ss.getSheetByName('Orders');
const activeSheetName = ss.getActiveSheet().getName();
const thisRow = e.range.getRow();
const thisCol = e.range.getColumn();
const cellValue = e.range.getValue();
if (activeSheetName == orderSheet.getName() && thisRow > 5 && thisCol < 13 && cellValue == 'Confirmed') {
moveOrder(ss, orderSheet, thisRow, dstSpreadsheetId, destSheetName)
orderSheet.getRange(thisRow, thisCol).setValue('')
}
}
}
function moveOrder(ss, orderSheet, thisRow, dstSpreadsheetId, destSheetName) {
const orderHeaders = orderSheet.getRange(5, 1, 1, 13);//Gets the table headers.
const rowValues = orderSheet.getRange(thisRow, 1, 1, 13);//Gets the changed row
const newSheet = ss.insertSheet('MoveOrderToWIP');//Creates a temporary sheet
orderHeaders.copyTo(newSheet.getRange(newSheet.getLastRow() + 1, 1), { contentsOnly: true });//Moves the headers into the temporary sheet
rowValues.copyTo(newSheet.getRange(newSheet.getLastRow() + 1, 1), { contentsOnly: true });//Moves the row into the temporary sheet
}
Thank you!
When I saw your updated script, it seems that dstSpreadsheetId and destSheetName are not used in moveOrder function. Although I cannot understand whether you wanted to use only one same Spreadsheet, for example, when you want to keep the edited range as the active range even when the new sheet is inserted by insertSheet, how about the following modification?
Issue and solution:
In your script, ss is const ss = SpreadsheetApp.getActiveSpreadsheet();. In this case, when insertSheet is used, the activated ranges are changed. In this case, even when ss is used as e.source, the same result occurs. It seems that this is the current specification.
When you want to keep the active range even when insertSheet is used, please use SpreadsheetApp.openById() instead of SpreadsheetApp.getActiveSpreadsheet(). By this, the active range is not changed even when insertSheet is used.
When this is reflected in your script, it becomes as follows. In this modification, your showing script is modified. Please be careful about this.
Modified script:
From:
const newSheet = ss.insertSheet('MoveOrderToWIP');
To:
const newSheet = SpreadsheetApp.openById(ss.getId()).insertSheet('MoveOrderToWIP');
By calling the Spreadsheet from outside, even when insertSheet is used, the active range can be kept. In this case, even when Sheets API is used, the same result occurs.
Note:
In your script, after "MoveOrderToWIP" sheet was inserted, the script is run again, an error occurs. Because the same sheet name is existing in the Spredsheet. So, please be careful this.
Reference:
openById(id)
All you need is from range and to range there is no need to actually activate the either of the sheets
fromRange.copyTo(toRange);
Probably the insertSheet() is making it the active sheet. So make some other the sheet the active sheet after doing the insert

When row is added it should keep all formulas

I have been trying to add a row which keep the formulas.
But when i add any row it always empty.
I could not found a way by searching on google.
I have attached below example sheet. Any help would be greatly appreciate
https://docs.google.com/spreadsheets/d/1HiOrz1KAuV1nN9a2IlwQgv3aWrGNKFaKHq2a8JZw3gI/edit#gid=0
Explanation:
Your goal is to copy the formulas to the newly inserted row upon inserting a new row.
You can use an onChange which has a property INSERT_ROW and
make sure you activate some code when you insert a new row.
The following script will copy the content and formulas from the above row of the one which was inserted to the newly inserted row upon inserting a new row.
Solution:
Add both code snippets below to the script editor:
function myFunction(e) {
const sh = SpreadsheetApp.getActiveSheet();
if(e.changeType === 'INSERT_ROW') {
const row = sh.getActiveRange().getRow();
var fromRng = sh.getRange(row-1,1,1,sh.getLastColumn());
var toRng = sh.getRange(row,1,1,sh.getLastColumn());
fromRng.copyTo(toRng);
}
}
and execute this function createTrigger only and once to create the onChange trigger:
function createTrigger(){
var sheet = SpreadsheetApp.getActive();
ScriptApp.newTrigger("myFunction")
.forSpreadsheet(sheet)
.onChange()
.create();
}
Illustration:
Limitation:
The disadvantage of this approach is that is copies both values and formulas, but it does not seem to matter in your case since you have only formulas as of now. If you want to put only formulas you need to use setFormulaR1C1 but since you have cells with no formulas, you need to make sure that you copy formulas, otherwise you will get errors.
This should let you copy your last row, including data and formula, into its next row.
function addRow() {
var sh = SpreadsheetApp.getActiveSheet();
var lastRow = sh.getLastRow();
var lastCol = sh.getLastColumn();
var range = sh.getRange(lastRow, 1, 1, lastCol);
sh.insertRowsAfter(lastRow, 1);
range.copyTo(sh.getRange(lastRow + 1, 1, 1, lastCol), {contentsOnly:false});
}
The important parameter you need in copyTo here is {contentsOnly:false}. Feel free to modify the coordinates for you to paste the row to anywhere.
For more details, read the usage of copyTo
If you want only the formula in the newly added row, you need to get the formula from the source row and then copy it to your destination row.
var source = sheet.getRange("A1:C1");
var dest = sheet.getRange("A2:C2");
var arr = source.getFormulas();
dest.setFormulas(arr);
This doesn't adjust the formula to the new row, it will copy the exact cell formula so be careful.

Dynamically updating rspreadsheet.getRange() column depending on the location of sheet with macro/script

I am trying to run a macro on Sheet1 for data validation on Sheet2 by dynamically updating the column. It selects the full column (except for the first row) in Sheet1 to then validate on that same column in Sheet2. As seen in the example spreadsheet.getRange('\'Sheet2'!$P$2:$P$9') is hardcoded to always use P2:P9. This is fine if I am validating the P column, how do I dynamically update this for when I start the script in column N?
function test2() {
var spreadsheet = SpreadsheetApp.getActive();
var currentCell = spreadsheet.getCurrentCell();
spreadsheet.getSelection().getNextDataRange(SpreadsheetApp.Direction.DOWN).activate();
currentCell.activateAsCurrentCell();
spreadsheet.getActiveRange().setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInRange(spreadsheet.getRange('\'Sheet2'!$P$2:$P$9'), false)
.build());
};
I believe your goal as follows.
You want to set the data validation rule to the active sheet using the column of "Sheet2" which is the same with the column selected at the active sheet.
For this, how about this answer?
Modification points:
In this modification, the A1Notation is retrieved from the selected range, and the column letter is retrieved from it. By this, the values for setting the data validation rule can be used from the selected column letter.
When your script is modified, it becomes as follows.
Modified script:
Pease copy and paste the following script. In order to use this script, please select the range on "Sheet1" and run this function myFunction. By this, the same column with the selected column is used from "Sheet2", and the data validation rule is set.
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive();
var currentCell = spreadsheet.getCurrentCell();
var range = spreadsheet.getSelection().getNextDataRange(SpreadsheetApp.Direction.DOWN).activate(); // Modified
var column = range.getA1Notation().split(":")[0].replace(/\d+/g, ""); // Added
currentCell.activateAsCurrentCell();
spreadsheet.getActiveRange().setDataValidation(SpreadsheetApp.newDataValidation()
.setAllowInvalid(false)
.requireValueInRange(spreadsheet.getRange(`'Sheet2'!$${column}$2:$${column}$9`), false).build()); // Modified
}
In this modification, the rows are used from 2 to 9 by your script. So when you want to modify this, please modify above script.
Reference:
getA1Notation()

How to copy a range of selected data to after the lastRow of data in the same Sheet using Google Apps Script?

I selected manually a range of data and want to press a button to copy those data to after the last row of data in the same sheet using Google Apps Script but not working at all. How to fix it? The codes are:
var listToCopy = SpreadsheetApp.getActiveSheet().getActiveRange();
var height = listToCopy.getHeight();
var destRow = listToCopy.getLastRow()+1;
listToCopy.copyTo(spreadsheet.getRange(destRow, 0, height));
I believe your goal as follows.
You want to copy the selected range to the last row of the same sheet using Google Apps Script.
For this, how about this answer?
Modification points:
In the case of var destRow = listToCopy.getLastRow()+1;, the last row of the range of listToCopy is retrieved.
In your case, the last row of the sheet is required to be retrieved.
The source range can be copied to the destination range as the start range like getRange(destRow, 1).
The 1st number of range is 1.
spreadsheet is not declared.
When above points are reflected to your script, it becomes as follows.
Modified script:
In order to use this script, please select the range and run the function of myFunction. By this, the selected range is copied to the last row of the same sheet.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var listToCopy = sheet.getActiveRange();
var destRow = sheet.getLastRow() + 1;
listToCopy.copyTo(sheet.getRange(destRow, 1));
}
References:
getLastRow() of Class Sheet
copyTo(destination)

After duplicating a sheet, remove formulas and retain values/formats

I have a sheet "SourceData" that has a lot of formulas to develop a proposal price based on variables entered on the sheet "Inputs". I need script to generateNewScope, where the "SourceData" sheet is duplicated, formulas removed from the duplicate, and it's renamed from "Copy of SourceData" to 1, then 2, then 3, etc.
I'm close! I can duplicate and rename, and I've gotten a different script to the point where it removes the formulas, but that one removed formulas from both "SourceData" AND "1". I just need to add additional actions here that essentially copy/paste values only directly in the same spot, or just a remove formulas action.
function generateNewScope() {
ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("SourceData"));
var ns = ss.duplicateActiveSheet(),
allSheets = ss.getSheets();
ns.setName(allSheets.length - 4);
}
You want to copy a sheet in a Spreadsheet.
You want to copy only values without the formulas.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this modification?
Modification points:
In this modification, your script is modified.
Only values are copied using copyTo() after the sheet was copied.
Modified script:
function generateNewScope() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.setActiveSheet(ss.getSheetByName("SourceData"));
var ns = ss.duplicateActiveSheet();
var range = ns.getDataRange(); // Added
range.copyTo(range, {contentsOnly: true}); // Added
allSheets = ss.getSheets();
ns.setName(allSheets.length - 4);
}
Reference:
copyTo()
If I misunderstood your question and this was not the result you want, I apologize.