Missing Headers row and Leaving space - google-apps-script

I was working with a combine sheets app script which is working fine at the spot by mereging A bunch of 36 sheetsinto one masterenter code here
the only flaw of the script is that it is not showing a common header row in the top and also leaving a space after data end from first sheets and so on >>>
here the code can anyone help a bit here
function combineSheets() {
var sApp = SpreadsheetApp.getActiveSpreadsheet();
var s1= sApp.getSheetByName("A1");
var s2= sApp.getSheetByName("A2");
var s3= sApp.getSheetByName("A3");
var s4= sApp.getSheetByName("A4");
var s5= sApp.getSheetByName("A5");
var s6= sApp.getSheetByName("A6");
var s7= sApp.getSheetByName("A7");
var s8= sApp.getSheetByName("A8");
var s9= sApp.getSheetByName("A9");
var s10= sApp.getSheetByName("A10");
var s11= sApp.getSheetByName("A11");
var s12= sApp.getSheetByName("A12");
var s13= sApp.getSheetByName("A13");
var s14= sApp.getSheetByName("A14");
var s15= sApp.getSheetByName("A15");
var s16= sApp.getSheetByName("A16");
var s17= sApp.getSheetByName("A17");
var s18= sApp.getSheetByName("A18");
var s19= sApp.getSheetByName("A19");
var s20= sApp.getSheetByName("A20");
var s21= sApp.getSheetByName("A21");
var s22= sApp.getSheetByName("A22");
var s23= sApp.getSheetByName("A23");
var s24= sApp.getSheetByName("A24");
var s25= sApp.getSheetByName("A25");
var s26= sApp.getSheetByName("A26");
var s27= sApp.getSheetByName("A27");
var s28= sApp.getSheetByName("A28");
var s29= sApp.getSheetByName("A29");
var s30= sApp.getSheetByName("A30");
var s31= sApp.getSheetByName("A31");
var s32= sApp.getSheetByName("A32");
var s33= sApp.getSheetByName("A33");
var s34= sApp.getSheetByName("A34");
var s35= sApp.getSheetByName("A35");
var s36= sApp.getSheetByName("A36");
var s37= sApp.getSheetByName("Master");
// If Master doesn't exist you'll need to create it here.
var s1values = s1.getRange(2,1,s1.getLastRow(),27).getValues();
var s2values = s2.getRange(2,1,s2.getLastRow(),27).getValues();
var s3values = s3.getRange(2,1,s3.getLastRow(),27).getValues();
var s4values = s4.getRange(2,1,s4.getLastRow(),27).getValues();
var s5values = s5.getRange(2,1,s5.getLastRow(),27).getValues();
var s6values = s6.getRange(2,1,s6.getLastRow(),27).getValues();
var s7values = s7.getRange(2,1,s7.getLastRow(),27).getValues();
var s8values = s8.getRange(2,1,s8.getLastRow(),27).getValues();
var s9values = s9.getRange(2,1,s9.getLastRow(),27).getValues();
var s10values = s10.getRange(2,1,s10.getLastRow(),27).getValues();
var s11values = s11.getRange(2,1,s11.getLastRow(),27).getValues();
var s12values = s12.getRange(2,1,s12.getLastRow(),27).getValues();
var s13values = s13.getRange(2,1,s13.getLastRow(),27).getValues();
var s14values = s14.getRange(2,1,s14.getLastRow(),27).getValues();
var s15values = s15.getRange(2,1,s15.getLastRow(),27).getValues();
var s16values = s16.getRange(2,1,s16.getLastRow(),27).getValues();
var s17values = s17.getRange(2,1,s17.getLastRow(),27).getValues();
var s18values = s18.getRange(2,1,s18.getLastRow(),27).getValues();
var s19values = s19.getRange(2,1,s19.getLastRow(),27).getValues();
var s20values = s20.getRange(2,1,s20.getLastRow(),27).getValues();
var s21values = s21.getRange(2,1,s21.getLastRow(),27).getValues();
var s22values = s22.getRange(2,1,s22.getLastRow(),27).getValues();
var s23values = s23.getRange(2,1,s23.getLastRow(),27).getValues();
var s24values = s24.getRange(2,1,s24.getLastRow(),27).getValues();
var s25values = s25.getRange(2,1,s25.getLastRow(),27).getValues();
var s26values = s26.getRange(2,1,s26.getLastRow(),27).getValues();
var s27values = s27.getRange(2,1,s27.getLastRow(),27).getValues();
var s28values = s28.getRange(2,1,s28.getLastRow(),27).getValues();
var s29values = s29.getRange(2,1,s29.getLastRow(),27).getValues();
var s30values = s30.getRange(2,1,s30.getLastRow(),27).getValues();
var s31values = s31.getRange(2,1,s31.getLastRow(),27).getValues();
var s32values = s32.getRange(2,1,s32.getLastRow(),27).getValues();
var s33values = s33.getRange(2,1,s33.getLastRow(),27).getValues();
var s34values = s34.getRange(2,1,s34.getLastRow(),27).getValues();
var s35values = s35.getRange(2,1,s35.getLastRow(),27).getValues();
var s36values = s36.getRange(2,1,s36.getLastRow(),27).getValues();
// Now, we can put out all together and stuff it in Master
var s37values = [];
s37values = s1values.concat(s2values,s3values,s4values,s5values,s6values,s7values,s8values,s9values,s10values,s11values,s12values,s13values,s14values,s15values,s16values,s17values,s18values,s19values,s20values,s21values,s22values,s23values,s24values,s25values,s26values,s27values,s28values,s29values,s30values,s31values,s32values,s33values,s34values,s35values,s36values);
s37.getRange(1,1,s37values.length,27).setValues(s37values);
}

Modification points:
About not showing a common header row in the top, in your script, all values are retrieved from the 2nd row. I thought that this might be the reason for your issue. From a common header row, in this modification, the header row is retrieved from the 1st sheet.
About also leaving a space after data end from first sheets and so on, I thought that the reason of your issue is due to getRange(2,1,s1.getLastRow(),27). In this case, the values are retrieved from 2nd row to the last row + 1 rows. In this case, it required to be getRange(2,1,s1.getLastRow() - 1,27).
In your script, I thought that the sheet names from "A1" to "A36" can be created using a script.
When these points are reflected in your script, it becomes as follows.
Modified script:
function combineSheets() {
var sApp = SpreadsheetApp.getActiveSpreadsheet();
var values = [...Array(36)].map((_, i) => `A${i + 1}`).flatMap((s, i) => {
var sheet = sApp.getSheetByName(s);
var lastRow = sheet.getLastRow();
if (i == 0) {
return sheet.getRange(1, 1, lastRow, 27).getValues();
}
return lastRow > 1 ? sheet.getRange(2, 1, lastRow - 1, 27).getValues() : [];
});
sApp.getSheetByName("Master").getRange(1, 1, values.length, 27).setValues(values);
}
The headr row is retrieved from the 1st sheet.
Note:
In this modification, it supposes that the sheet names of "A1" to "A36" and "Master" are existing in your Spreadsheet. Please be careful about this.
From a common header row in the top, this script supposes that your all sheets have the same header row. Please be careful about this.
About Exception: The number of rows in the range must be at least 1. AT HERE................var values = [...Array(36)].map((_, i) => A${i + 1}).flatMap((s, i) => { var sheet = sApp.getSheetByName(s); return sheet.getRange(i == 0 ? 1 : 2, 1, sheet.getLastRow() - (i == 0 ? 0 : 1), 27).getValues(); , from your question, I had thought that your all sheets have the values. But from your reply, it seems that my understanding was not correct. So, I updated my proposed script. Could you please confirm it?
References:
getRange(row, column, numRows, numColumns)
map()

Related

Apps Script Google Sheets Formatting

I have a script that creates a new Google Sheet file and names it based on a variable in a different sheet. After the sheet is created I am trying to copy all data from a template sheet, including merged cells and formatting. The scrip currently works in all aspects except the formatting. I am having a very hard time to get it to work. I would even be fine with just duplicating the sheet and having it rename based on my previous criteria.
function createNewSheet(e) {
const sh = e.range.getSheet();
var name = sh.getRange(e.range.rowStart, 1).getValue();
var crNew = SpreadsheetApp.create("Job Traveler-" + name);
var ssNew = SpreadsheetApp.openByUrl(crNew.getUrl()).getId();
importRange("1X4iOzc_shcOR8UM7OEM4F1-eR62YZmwKWyyEuu59Pf4","Job!A1:D", ssNew,"Sheet1!A1");
}
function importRange(sourceId,sourceRange,destinationID,destinationRangeStart) {
var sourceSS = SpreadsheetApp.openById(sourceId);
var sourceRng = sourceSS.getRange(sourceRange);
var sourceVals = sourceRng.getValues();
var destinationSS = SpreadsheetApp.openById(destinationID);
var destStartRange = destinationSS.getRange(destinationRangeStart);
var destSheet = destinationSS.getSheetByName(destStartRange.getSheet().getName());
var row = destStartRange.getRow();
var col = destStartRange.getColumn();
var rows = sourceVals.length;
var cols = sourceVals[0].length;
destSheet.getRange(row,col,rows,cols).setValues(sourceVals);
var merged = sourceRng.getMergedRanges();
var rowOffset = destStartRange.getRow()-sourceRng.getRow();
var columnOffset = destStartRange.getColumn()-sourceRng.getColumn();
for( var i=0; i<merged.length; i++ ) {
row = merged[i].getRow()+rowOffset;
col = merged[i].getColumn()+columnOffset;
rows = merged[i].getNumRows();
cols = merged[i].getNumColumns();
destSheet.getRange(row,col,rows,cols).merge();
}
}
Any advice would be much appreciated. I am no expert so I do apologize.
Best
Here is a snippet from one of my projects where I set the border and fill color
for (i = 0; i < numCount; i++) {
sheet.getRange(i + row2SetValues, col2SetValues).setValue(randNumbers[i]);
}
sheet.getRange(row2SetValues, col2SetValues, numCount, 1).setBorder(true, true, true, true, true, true, 'black', SpreadsheetApp.BorderStyle.SOLID_LIGHT);
sheet.getRange(row2SetValues, col2SetValues, numCount, 1).setBackground("#bdd4f9");
}

TypeError: lastrow.setValues is not a function

I'm trying to copy past a particular range to another spreadsheet serving as a database. The goal is to copy past values that are in the range(a43:n54), to the last row of the database page, then to clear the range (d11:n22) of the source sheet.
I've already used part of code I saw on another thread (the get/set values part). But here when I run the function, it says that line 35 "lastrow.setValues(values) is not a function". I know it means my function is not valid and most likely it will do the same with all the setValues section...
function myfunction()
{
// spreadsheet identification
const sourcesheet = SpreadsheetApp.getActiveSpreadsheet();
const destination = SpreadsheetApp.openByUrl("page_url")
// identification of the ranges to copy and to delete
const ws = sourcesheet.getSheetByName ("Récap");
const source_range_to_delete = ws.getRange("d11:n22");
const source_range_to_copy = ws.getRange("a43:n54");
// get last row of target spread sheet
const destpage = destination.getSheetByName("Feuille 1");
var destrange =destpage.getRange("A1:n").getValues();
var lrIndex;
for( var i = destrange.length-1;i>=0;i--){
lrIndex = i;
if(!destrange[i].every(function(c){ return c == "";})) {
break;
}
}
var lastrow =lrIndex +1;
//get values
var values = source_range_to_copy.getValues()
var bGcolors = source_range_to_copy.getBackgrounds();
var colors = source_range_to_copy.getFontColors();
var fontSizes = source_range_to_copy.getFontSizes();
// set values
lastrow.setValues(values);
lastrow.setBackgrounds(bGcolors);
lastrow.setFontColors(colors);
lastrow.setFontSizes(fontSizes);
source_range_to_delete.clearContent({contentsOnly:true});
}
function myfunction() {
// spreadsheet identification
const sourcesheet = SpreadsheetApp.getActiveSpreadsheet();
const destination = SpreadsheetApp.openByUrl("page_url");
// identification of the ranges to copy and to delete
const ws = sourcesheet.getSheetByName("Récap");
const source_range_to_delete = ws.getRange("d11:n22");
const source_range_to_copy = ws.getRange("a43:n54");
// get last row of target spread sheet
const destpage = sourcesheet.getSheetByName("Feuille 1");
var data = sourcesheet.getRange("a1:n").getValues();
for (var lastrow = data.length-1; lastrow >= 0; lastrow--) {
if (data[lastrow].some(c => c != "")) break;
}
//get values
var values = source_range_to_copy.getValues();
var bGcolors = source_range_to_copy.getBackgrounds();
var colors = source_range_to_copy.getFontColors();
var fontSizes = source_range_to_copy.getFontSizes();
// set range right after the last row on destination sheet
var destrange = destpage.getRange(lastrow + 2,1,values.length,values[0].length);
// set values of destination range
destrange.setValues(values);
destrange.setBackgrounds(bGcolors);
destrange.setFontColors(colors);
destrange.setFontSizes(fontSizes);
source_range_to_delete.clearContent();
}
setValues() is a method of class Range. lastrow is an integer.

Double the variables in move script (Google)

For my work I am trying to automatically move a marked line to a 'Historie' sheet. I have currently managed to follow an example and use 1 variable (see copy).
Now I want 2 variables. Instead of just column K -> Completed, I also want to add that column J needs to be True!
function onEdit(event){
var url = "https://docs.google.com/spreadsheets/d/1per7L2wPkMKrzVgv5npQ-2RQ8fkWzslo09Ntlzy4qAs/edit?ts=6034e66e#gid=0";
var source_sheet_name = "Werklijst";
var target_sheet_name = "Historie";
var columnLetter = "J";
var ss= SpreadsheetApp.openByUrl(url);
var source_sheet = ss.getSheetByName(source_sheet_name);
var target_sheet = ss.getSheetByName(target_sheet_name);
var source_range = source_sheet.getRange(columnLetter+":"+columnLetter).getValues();
for(var i = source_range.length-1; i >= 0;i--){
if(source_range[i]=="COMPLETE"){
var targetRange = target_sheet.getRange(target_sheet.getLastRow() + 1, 1);
source_sheet.getRange((i+1), 1, 1, source_sheet.getLastColumn()).moveTo(targetRange);
source_sheet.deleteRow((i+1));
}
}
}
Here is the link to a copy of said sheet (it is in Dutch).
The obvious solution would be to do something like that:
var columnLetter1 = "K";
var columnLetter2 = "J";
var source_range1 = source_sheet.getRange(columnLetter1+":"+columnLetter1).getValues();
var source_range2 = source_sheet.getRange(columnLetter2+":"+columnLetter2).getValues();
and then change the if statement to:
if(source_range1[i]=="COMPLETE" && source_range2[i]==true)
Full snippet of the user's code with the modification points:
function onEdit(event){
var url = "https://docs.google.com/spreadsheets/d/1per7L2wPkMKrzVgv5npQ-2RQ8fkWzslo09Ntlzy4qAs/edit?ts=6034e66e#gid=0";
var source_sheet_name = "Werklijst";
var target_sheet_name = "Historie";
var columnLetter1 = "K";
var columnLetter2 = "J";
var ss= SpreadsheetApp.openByUrl(url);
var source_sheet = ss.getSheetByName(source_sheet_name);
var target_sheet = ss.getSheetByName(target_sheet_name);
var source_range1 = source_sheet.getRange(columnLetter1+":"+columnLetter1).getValues();
var source_range2 = source_sheet.getRange(columnLetter2+":"+columnLetter2).getValues();
for(var i = source_range.length-1; i >= 0;i--){
if(source_range1[i]=="COMPLETE" && source_range2[i]==true){
var targetRange = target_sheet.getRange(target_sheet.getLastRow() + 1, 1);
source_sheet.getRange((i+1), 1, 1, source_sheet.getLastColumn()).moveTo(targetRange);
source_sheet.deleteRow((i+1));
}
}
}
Keep in mind that the current code is not very optimal since you don't use the event object anywhere in your code. The latter will help you get info regarding the edits.
For example, right now your whole code will be executed upon every edit in any cell in the entire spreadsheet file. If you use the event object you can execute some code upon edits on a particular sheet (e.g. Werklijst) and on particular cells (e.g. cells in column K or J). In this way your code will be way faster and more efficient.

Add the time when one google sheets document is modified to another sheets document

I have one sheet for a group of people. I'm trying to make a script so that whenever they edit the sheet, the time that they last edited will show up in a sheet in another document.
A sample row from the group sheet looks like this:
col1|...|col10|person name|...|col17
and the sheet that the time should be going to looks like this:
person name|col2|...|col10|date last edited.
this is the code that I've been trying and it is not working so far:
function onEdit(e) {
var row = e.range.getRow();
var col = e.range.getColumn();
var time = new Date().toLocaleString("en-US", {timeZone: "America/Toronto"})
var ID = "sheet ID"; //The ID for the second sheet goes here
var sheet = SpreadsheetApp.OpenById(ID);
var target = sheet.getSheetByName("Sheet2");
var lastColumn = target.getLastColumn();
var lastRow = target.getLastRow();
var range = target.getRange(1,1,lastRow, lastColumn);
var data = range.getValues();
var userEmail = e.user.getEmail();
var array = userEmail.split(".");
var firstName = array[0];
var secondSheet = e.source.getActiveSheet();
var lastRowSecond = secondSheet.getLastRow();
var lastColumnSecond = secondSheet.getLastColumn();
var secondRange = secondSheet.getRange(1,1,lastRowSecond, lastColumnSecond);
var secondData = secondRange.getValues();
var nameRow = secondData[row-1];
var nameColumn = nameRow[10];
var secondPersonarray = nameColumn.split(" ");
var secondPersonFirstName = secondPersonarray[0];
for (var i=1; i<lastRow; i++) {
var sheetRow = data[i];
var name = sheetRow[0].split(" ");
var firstNameSheet = name[0];
if ((firstName == firstNameSheet) && (firstName == secondPersonFirstName)) {
target.getRange(sheetRow, 10).setValue(time);
}
}
}
I've done something similar, only with one document, so I know the problem isn't with the time.

Google Sheets: getting a sheet by its index

I am trying to get a sheet using a calculated index. I am having a problem but am unsure whether it's a problem converting a float to an integer or if there is a syntax error. What am I getting wrong?
function copySheetValues()
{
var spread = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = SpreadsheetApp.getActiveSheet();
//get the source sheet data
var sourceDataRange = sourceSheet.getDataRange();
var sourceSheetValues = sourceDataRange.getValues();
var sourceRows = sourceDataRange.getNumRows();
var sourceColumns = sourceDataRange.getNumColumns();
// get the source sheet index and set the next sheet index
var sourcesheetIndex = sourceSheet.getIndex();
var destinationsheetIndex = Math.round(sourcesheetIndex + 1);
// get the next sheet
var destinationSheet = spread.getSheets()[destinationsheetIndex]
//destination.insertSheet(sourcename, 0);
destinationSheet.getDataRange().offset(0, 0, sourceRows, sourceColumns).setValues(sourceSheetValues);
}
As getIndex() is 1 based and getSheets() is 0 based you might try:
var destinationSheet = spread.getSheets()[sourceSheet.getIndex()];
go figure
Caveat: getIndex() returns the sheets position within the spreadsheet where getSheets() has to do with the order in which the sheets were added and the two may not correspond if the spreadsheet has been rearranged after the sheets were added.
To insure that the destination sheet is the sheet located just after the source sheet:
// get the source sheet index and set the next sheet index
var destinationsheetIndex = sourceSheet.getIndex() + 1;
// get the next sheet
var sheets = spread.getSheets();
for (var i=0; i<sheets.length; i++) {
if(sheets[i].getIndex() == destinationsheetIndex ) {
var destinationSheet = sheets[i];
break;
};
};