How to display the values in columns in Google app script - google-apps-script

I got the output as below (row wise):
one
two
three
But I would like to display the value as below (column wise, single value in each cell):
one two three
Can any one please tell me how can I achieve this using getRange function in Google app script ?
Thanks.

Unless you are setting only 1 value, I recommend using getRange(startRow, startCol, numRows, numCols) together with Range class methods getValues() and setValues().
getValues() produces a 2d array which you can access with indexes (let's use integer variables row and col in our example) data[row][col]
So let's say you wish to set one, two, three to column A, B and C in row 1, then you simply have to do
var targetRange = SpreadsheetApp.getActiveSheet().getRange(1, 1, 1, 3)
var data = [['One', 'Two', 'Three']]
targetRamge.setValues(data)
Now let's say I want to write One, Two and Three into Column A over rows 1 2 and 3 then it is only slightly different:
var targetRange = SpreadsheetApp.getActiveSheet().getRange(1, 1, 3, 1) //we now get 1 column, but 3 rows
var data = [['One'], ['Two'], ['Three']] //Each array inside of the main array is a new row
targetRamge.setValues(data)
And there you have it. Simply manipulate the data as a 2D array all the time and use .getValues() and .setValues() with a range that uses multiple rows and/or columns.

Not sure if this is helpful. Have you heard about appendRow()? This will add your array to the last row of the sheet.
function append() {
var arr = ["a","b","c"]
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Entities')
sheet.appendRow(arr)
}

Related

Google apps script select specific columns to upload into target sheet

Total beginner here. I am trying to select columns A,B,C from spreadsheet B which has around 40K rows and 25 columns, to spreadsheet A which is a blank document. So, I have two spreadsheets.
This code works fine but I want to select only the columns I need (columns including all the data, not just the headers).
function importdata() {  
let ss = SpreadsheetApp.openById("ID"); //SPREADSHEET TO COPY FROM  
let sheet = ss.getSheetByName("name"); //SHEET (TAB) TO COPY FROM  
sheet.getRange(1,1,sheet.getLastRow(),sheet.getLastColumn()).getValues();
let ssThis = SpreadsheetApp.getActiveSpreadsheet();
let sheetRawData = ssThis.getSheetByName("name"); //SHEET IN THE TARGET SPREADSHEET TO COPY TO
sheetRawData.getRange(1,1,sheetRawData.getLastRow());
}
Any idea as to how I can add this into the code above?
Many thanks!
You can create an array of selected columns and get / set the values for the ranges corresponding to those columns:
function importSelectedColumns() {
let selectedColumns = [1, 3, 5];
let ss = SpreadsheetApp.openById("ID"); //SPREADSHEET TO COPY FROM
let sheet = ss.getSheetByName("name"); //SHEET (TAB) TO COPY FROM
let ssThis = SpreadsheetApp.getActiveSpreadsheet();
let sheetRawData = ssThis.getSheetByName("name"); //SHEET IN THE TARGET SPREADSHEET TO COPY TO
selectedColumns.forEach(function(column){
let data = sheet.getRange(1,column, sheet.getLastRow(),1).getValues();
sheetRawData.getRange(1,column, sheet.getLastRow(), 1).setValues(data);
})
}
Explanation:
forEach() is one of several possibilities to loop through several columns subsequently.
getRange(row, column, numRows, numColumns) lets you specify the number and amount of columns to retrieve.
setValues(values) allows you to import the data from one range into another one.
Note: The range dimensions of the origin and destination ranges need to match.
Additional information:
If you would like to paste your data into an adjacent range starting with column 1, one possible way based on the sample above would be to redefine the loop as following:
selectedColumns.forEach(function(column,i ){
let data = sheet.getRange(1,column, sheet.getLastRow(),1).getValues();
sheetRawData.getRange(1,1+i, sheet.getLastRow(), 1).setValues(data);
})
Thereby the counter variable i is introduced and the notation of the destination column is modified from column to 1+i, meaning that the columns will be set starting with column 1 and increasing by 1 for each loop iteration.

Copy specific Columns data from Last Row and paste to another sheet

I was trying to copy/fetch data from specific columns of the last row from my "Total" sheet, and pass those to another sheet named "vnSheet". The code below which i found earlier works fine. But, it copies all the row & column data from the mother sheet, which I don't want to happen.
function copySheet() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Total");
var destSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("vnSheet");
var columns_to_be_copied = ['A', 'B', 'D', 'F'];
var columns_to_be_pasted = ['A', 'B', 'D', 'F'];
for (column in columns_to_be_copied) {
var copy_range_string = columns_to_be_copied[column] + ':' + columns_to_be_copied[column];
var paste_range_string = columns_to_be_pasted[column] + ':' + columns_to_be_pasted[column];
var source = sourceSheet.getRange(copy_range_string);
var destination = destSheet.getRange(paste_range_string);
source.copyTo(destination, {contentsOnly:true});
}
}
Here, I want to Copy 'A', 'B', 'D', 'F'(except 'C' & 'E' ) column data only from Last row of "Total" and paste those data into the same columns of the "vnSheet" but in the Last row. I searched almost all over the internet and found no solution of my problem, all I found was similar to the code above.
As I'm new to this, my coding experience is limited but I'm a gd learner :) Any help to solve that problem will be greatly appreciated.
Thank you.
So there are a few things
You currently are not getting the last row, as far as I can tell
You currently have duplicate variables to hold the same array
You currently are copying an entire row, which is not what you want
Assuming there are already values in columns C and E in your Target Sheet there are a few ways to approach a solution:
You get the existing values from Target Sheet and then overwrite the columns you want to overwrite, then you update the entire row using one array
You only overwrite the particular cells you want to update, leaving the rest as is
Option 1 above will be quicker, but we are speaking fractions of a second.
Therefore I recommend option 2, as it does not touch an existing row with field you don't want to change.
My proposal is here:
function copyHandler(){
const activeSheet = SpreadsheetApp.getActive()
var sourceSheet = activeSheet.getSheetByName("Total");
const sourceLastRowNum = sourceSheet.getLastRow()
var destSheet = activeSheet.getSheetByName("vnSheet");
const destLastRowNum = destSheet.getLastRow() + 1
const lastRow = sourceSheet.getRange(sourceLastRowNum, 1, 1, 6).getValues()[0]
lastRow.forEach( (value, index) => {
// Skip column C and column E
if( index == 2 || index == 4) return
destSheet.getRange(destLastRowNum, index+1).setValue(value)
})
}
Use sourceSheet.getLastRow() before the for loop to get the row number of the last row in your "Total" sheet, then add this value after each column letters.
Let's say that you assign the result of the above to a lastRow, then you can use this variable this way:
var copy_range_string = columns_to_be_copied[column] + lastRow + ':' + columns_to_be_copied[column] + lastRow;
NOTE:
You might find helpful to read https://developers.google.com/apps-script/guides/support/best-practices. This article suggest to avoid doing calls to Google Apps Script classes as they are slow. One way to reduce the number of calls do achieve the result that you are looking is by using getRangeList at it allows to get multiple ranges at once. Another way is by using the Advanced Sheets Service as it allow to do batch updates.

Copy data range and paste to new page, and repeat

I am trying to copy a range from sheet 'Full' and paste the values only to a new sheet, 'Dump'. While the macro below does its action once, I am regenerating the original data range (Full), so I want to copy that new set and append to the same output page, indexed down to a blank row and keeping the first pasted data. Also then to do this 100 times.
The recoded macro is below, and I need to understand the script to add in to;
repeat the copy/paste function 100 times, and also
offset the paste range by a set number of rows.
Sorry, genuine newbie at editing google sheet macros. The Excel macro I use doesn't translate over.
Appreciate any answers you have.
function xmacro() {
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('A1').activate();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Full'), true);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Dump'), true);
spreadsheet.getRange('Full!BK3:BT34').copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);```
};
Your macro is just an automatically generated app script. You can extend its functionality by building off that with some more code. First I'll explain some of the basic concepts, if you know this, then just skip down to the code.
Sheets Concepts
Here are some basic concepts that took me forever to figure out because most of the documentation assumes you are already proficient at Javascript.
A range is a 2 dimensional array that has one array for each row, and the contents of that array are the columns:
someRange = [
[row1Col1, row1Col2, row1Col3, row1Col4],
[row2Col1, row2Col2, row2Col3, row2Col4],
[row3Col1, row3Col2, row3Col3, row3Col4]
]
To access a specific value you need to reference the row array, and then the index of the column you want.
Think about it like hotel room numbers. The first part of the number is the floor,
and the second part is the specific room on that floor.
You access arrays by calling the array name, then square brackets with the index number of the element you want.
Arrays are indexed starting at 0, so to get row 1 you would use:
someRange[0] would return the inner array [row1Col1, row1Col2, row1Col3].
But that doesn't give you a specific cell values - so you would use a second set of brackets to access the column in that row:
someRange[0][1] = 'row1Col2'
Arrays also have built in information, so you can find the length of an array by using Array.length no parenthesis.
Since the rows are in the outer array, you can get the number of rows by seeing how many inner arrays there are.
someRange.length = 3 There are 3 row arrays in the someRange array.
You can do the same with columns, since the number of columns is equal to the number of elements in an array. To get the number of elements in the first row you would use:
someRange[0].length - which would be 4
And since a range has the same number of columns for each row, you can pick any row
to get the number of columns (generally, there are always exceptions)
The Code
The first function will create a custom menu item to run the code.
// create a new menu item for your custom function
function onOpen(){
SpreadsheetApp.getUi().createMenu()
.addItem('100 Copies', 'lotsOfCopies')
.addToUi();
}
function lotsOfCopies() {
var ss = SpreadsheetApp.getActive();
var copySheet = ss.getSheetByName('yourCopySheetName');
var pasteSheet = ss.getSheetByName('yourPasteSheetName');
// the range you wish to copy, change to fit your needs
var copyRange = copySheet.getRange('A1:B7');
var copyValues = copyRange.getValues();
var copyRows = copyValues.length;
var copyCols = copyValues[0].length;
// define the first row to be pasted into
var pasteRow = 1;
// define the left side column of the range to be pasted into
var pasteCol = 1
// build a loop that does the same thing 100 times,
// and each time offsets the paste range by the number of rows in the copy range
for (var i = 0; i < 100; i++) {
// for every iteration after the first,
// add the number of rows in the copy range to the variable 'row'
// example if there are 10 rows in the copy range then
// iteration 1 row = 1 Iterartion 2 row = 11, Iteration 3 row = 21
if (i > 0) {
pasteRow = +pasteRow + +copyRows
}
// build the range to paste into - it starts on pasteRow and paste col,
// and is as many rows as the copied range, and as many columns as the copied range
let pasteRange = pasteSheet.getRange(pasteRow, pasteCol, copyRows, copyCols);
// put the values from copyValues into the pasteRange
pasteRange.setValues(copyValues);
}
}
function xmacro() {
const ss = SpreadsheetApp.getActive();
const ssh = ss.getSheetByName('Full')
const dsh = ss.getSheetByName('Dump')
ssh.getRange('BK3:BT34').copyTo(dsh.getRange('A1'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
}

Find last row with Data in Column D starting the search at Row 4 in Google App Script

I'm trying to find a way to find the last row with data in Column D. I also want the search to start at Row 4.
I'm really struggling and would appericate any help please.
You can refer to this code:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet2');
var rowOffset = 3;
var count = sheet.getRange('D4:D').getDisplayValues().flat().filter(String).length;
var lastRow = count+rowOffset;
Logger.log(lastRow);
What it does?
Select Range D4:D and get its value, since you want to get the last row with data in column D starting at row 4.
Use array.flat() to change 2-d array into 1-d array.
Use array.filter() to remove empty values. Then get it's array length
To get the last row index, Use the cell count that has data which we obtained in step 3 and add it to 3 (start offset since we start our search at row 4)
Note:
This solution will only work assuming you don't have empty rows in between.
Output:
Execution log
2:01:53 AM Notice Execution started
2:01:54 AM Info 13.0
2:01:55 AM Notice Execution completed
There are many ways to find the last value in a column, but here is one. See if this helps!
function myFunction() {
const spreadsheet = SpreadsheetApp.openByUrl('Insert Sheet URL Here');
const sheet = spreadsheet.getSheetByName('Insert Sheet Name Here - e.g. Sheet1');
const lastSheetRow = sheet.getLastRow();
let lastColumnRow = 'This column is empty';
let reversedColumnValues = sheet.getRange(1, 4, lastSheetRow).getValues().reverse();
for (index in reversedColumnValues) {
if (reversedColumnValues[index][0] != '') {
lastColumnRow = lastSheetRow - index;
break;
}
}
Logger.log(lastColumnRow);
}
This Apps Script Video may help you out too: https://www.youtube.com/watch?v=1Po1QElOFPk

Autofill google forms based on user input

Alright stack friends,
I'm working on my first projects using google scripts and it's been pretty fun so far. My project is to create a form for data entry that can either accept an ID number and fill in the rest of the fields, or let the user fill out the entire form. Basically my method to fill in the other fields is just to have a lookup table on the second sheet. When the user submits a form, the script runs, looks for the ID of the last row, scans the reference table for the ID, and then fills in the details.
I think the problem I'm having is the assumption that the data from the form is already in the sheet when the script runs. The problem I noticed is that the script sometimes fails to fill in the gaps. I tried creating form submissions in a loop with the same ID and they function somewhat erratically but it seems like the last sumbission always works which would make sense if the script executions are not matching up with the form submissions. Here's the script for reference:
function fillGaps() {
// First take in the appropriate spreadsheet objects and get the sheets from it
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheets()[0];
var refSheet = ss.getSheets()[1];
// Here's the last rows' index
var lastRow = sheet.getLastRow();
var lastRowRef = refSheet.getLastRow();
// now this is an array of values for the last row and the student ID entered
var response = sheet.getRange(lastRow, 1, 1, 7).getValues();
var enteredID = response[0][1];
// Next we're going to try to load up the lookup table and scan for the ID
var stuIDs = refSheet.getRange(2, 4, refSheet.getLastRow()).getValues();
var row = 0;
while(enteredID != stuIDs[row] && row <= lastRowRef){
row++;
}
// Okay at this point the row variable is actually -2 from what the sheet index
// is that I'm thinking of. This is because we didn't load the first row (names)
// and the way arrays are indexed starts with 0.
row++;
row++;
// now assuming that it found a match we'll fill in the values
if(row < refSheet.getLastRow()){
// Alright now we need to wrangle that row and format the data
var matchedRow = refSheet.getRange(row, 1, 1, 6).getValues();
// modify the response
var replacement = [response[0][0],enteredID, matchedRow[0][1],matchedRow[0][0],matchedRow[0][2],matchedRow[0][4],matchedRow[0][5]];
sheet.getRange(lastRow, 1, 1, 7).setValues([replacement]) ;
}
}
So I'm wondering:
Does this seem like the right diagnosis?
If so, what would be the best way to remedy? I thought of adding a little delay into the script as well as trying to capture the submissions timestamp (not sure how to do that)
Thank you much!
The following code gives a 2D array:
var stuIDs = refSheet.getRange(2, 4, refSheet.getLastRow()).getValues();
Also,refSheet.getLastRow gives the last row, lets say it is 10 in this case. The syntax for getRange is getRange(row, column, numRows) and the last argument is the number of rows, not the last column. So in the above code the selected range would be row 2 - 11 rather than 2- 10. Unless that is what you intended, modify the code like so:
var stuIDs = refSheet.getRange(2, 4, refSheet.getLastRow()-1).getValues();
To access the values in stuIDs you should use stuIDs[row][0] (2D array) to check for matching ID. Assuming your ID was to be matched was in column 1.
Secondly, in the loop you are using the following to check for the last index in array row <= lastRowRef which will cause it go out of range(because array starts at 0 and sheet row at 1) instead use this row < stuIDs.length
Finally, in case you don't find a match you will end up with the last row and your code will end you taking the last row as the matched index. This can be prevented by using a boolean variable to check for a match.
var foundId = false
var row = 0;
var i = 0;
for (i in stuIDs){
if(stuIDs[i][0] == enteredID)
foundID = true
break
}
}
row = i + 2
if (foundID){
var matchedRow = refSheet.getRange(row, 1, 1, 6).getValues();
// modify the response
var replacement = [response[0][0],enteredID, matchedRow[0][1],matchedRow[0][0],matchedRow[0][2],matchedRow[0][4],matchedRow[0][5]];
sheet.getRange(lastRow, 1, 1, 7).setValues([replacement]) ;
}
PS: You can also use event objects to get the values of response (eventObj.values). As mentioned here: https://developers.google.com/apps-script/guides/triggers/events
Hope that helps!