Google Sheets Apps Script Matching Source Destination Sheets having same name tabs - javascript

I've a need to copy values between tabs of source & destination sheets. The tabs are same name H1, H2, H3 in both sheets. Copying is between tabs of same name i.e., H1->H1, H2->H2, etc. The script is attached below. Every time I've to run the script, I'm changing the sheet name manually. How to do it in one go?
function updateSourceToTarget(sourceID,sourceName,targetID,targetname){
var source = SpreadsheetApp.openById("Source").getSheetByName("H1");
var destination = SpreadsheetApp.openById("Dest").getSheetByName("H1");
var sourcelastRow = source.getLastRow();
var sourcelastCol = source.getLastColumn();
var sourcedata = source.getRange(1,1,sourcelastRow,sourcelastCol).getValues();
destination.getRange(1,1,sourcelastRow,sourcelastCol).setValues(sourcedata);
}

Explanation:
Iterate over an array of the sheet names ["H1","H2","H3"] with a forEach loop.
Put all the sheet names in that array, and the script will take care of the task for every set of source and destination sheet.
Solution:
function updateSourceToTarget(sourceID,sourceName,targetID,targetname){
const sheetNames = ["H1","H2","H3"];
sheetNames.forEach(h=>{
let source = SpreadsheetApp.openById("Source").getSheetByName(h);
let destination = SpreadsheetApp.openById("Dest").getSheetByName(h);
let sourcelastRow = source.getLastRow();
let sourcelastCol = source.getLastColumn();
let sourcedata = source.getRange(1,1,sourcelastRow,sourcelastCol).getValues();
destination.getRange(1,1,sourcelastRow,sourcelastCol).setValues(sourcedata);
});
}
and I guess this is the final version that uses the function parameters:
function updateSourceToTarget(sourceID,targetID){
const sheetNames = ["H1","H2","H3"];
sheetNames.forEach(h=>{
let source = SpreadsheetApp.openById(sourceID).getSheetByName(h);
let destination = SpreadsheetApp.openById(targetID).getSheetByName(h);
let sourcelastRow = source.getLastRow();
let sourcelastCol = source.getLastColumn();
let sourcedata = source.getRange(1,1,sourcelastRow,sourcelastCol).getValues();
destination.getRange(1,1,sourcelastRow,sourcelastCol).setValues(sourcedata);
});
}

Related

Can I use Google Apps Script to replace text across multiple tabs in a Google Sheet?

I am building on a previous project in which I have a Google Form which takes responses in a Google Sheet and uses a template Sheet to populate the Form responses and have that generate a new Sheet document. This is a very dumbed-down version of what I'm trying to execute in reality, but the goals remain the same: I am trying to replace text across multiple tabs in the template Sheet when generating a new one.
Currently, in my Apps Script, I have code which is successfully able to make a copy of the template file and name it accordingly:
//Enter collected info into Requirements Template
const googleSheetTemplate = DriveApp.getFileById('1wqCwMhpuDLReU1hE1CbcDL-Vdw_4zge1xM6oOl34Ohg');
const destinationFolder = DriveApp.getFolderById('1GxNZQmP8mxHBhVl5AMoqBFs8sAIYzcm3');
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 2');
const copy = googleSheetTemplate.makeCopy(`${row[3]}, ${row[0]} Vehicle Order` , destinationFolder);
const newSheet = SpreadsheetApp.openById(copy.getId());
const A1 = newSheet.getDataRange();
And the next few lines which are meant to be able to find and replace certain strings within the newly copied Sheet are as follows:
A1.createTextFinder("{{Customer}}").replaceAllWith(row[3]);
A1.createTextFinder("{{Car}}").replaceAllWith(row[1]);
A1.createTextFinder("{{Color}}").replaceAllWith(row[2]);
A1.createTextFinder("{{Delivery}}").replaceAllWith(row[5]);
The issue I am experiencing is that the first tab of the Sheet gets populated, but the second tab does not.
Is there more I must add somewhere in order to get the second tab filled out? Is this even possible in Google Apps Script?
Entire code below:
function myFunction() {
// get the spreadsheet information
const ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
//const responseSheet = ss.getSheetByName('Form Responses 2');
const data = ss.getDataRange().getValues();
//console.log(data);
// Loop over the rows
data.forEach((row,i) => {
// Identify whether notification has been sent
if (row[4] === '') {
// Get the Form info
var emailTo = "jeffreyabr#gmail.com"
var subject = 'Car Request';
const Timestamp = row[0];
var Car = row[1];
var Color = row[2];
var requestor = row[3]
var delivery = row[5];
//Form variable declarations
formTime = Timestamp;
formCar = Car;
formColor = Color;
formName = requestor;
formDelivery = delivery;
//Enter collected info into Requirements Template
const googleSheetTemplate = DriveApp.getFileById('1wqCwMhpuDLReU1hE1CbcDL-Vdw_4zge1xM6oOl34Ohg');
const destinationFolder = DriveApp.getFolderById('1GxNZQmP8mxHBhVl5AMoqBFs8sAIYzcm3');
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Form Responses 2');
const copy = googleSheetTemplate.makeCopy(`${row[3]}, ${row[0]} Vehicle Order` , destinationFolder);
const newSheet = SpreadsheetApp.openById(copy.getId());
const A1 = newSheet.getDataRange();
A1.createTextFinder("{{Customer}}").replaceAllWith(row[3]);
A1.createTextFinder("{{Car}}").replaceAllWith(row[1]);
A1.createTextFinder("{{Color}}").replaceAllWith(row[2]);
A1.createTextFinder("{{Delivery}}").replaceAllWith(row[5]);
const orderLink = newSheet.getUrl();
//Add URL to Sheet
sheet.getRange(i + 1, 7).setValue(orderLink)
orderBlob = [];
//Get the blob of order attachment
if(row[6]){
var order1 = row[6].split(', ');
order1.forEach(url => {
var orderFileId = url.replace('https://drive.google.com/open?id=','');
var orderFile = DriveApp.getFileById(orderFileId);
orderBlob.push(orderFile.getBlob());
});
}
let body = '';
// Generate email
var html = HtmlService.createTemplateFromFile("email.html");
var htmlText = html.evaluate().getContent();
// Send email
GmailApp.sendEmail(emailTo, subject, body, {htmlBody: htmlText, attachments: orderBlob})
// Mark as Notified
const g = 'Notification sent';
ss.getRange(i + 1,5).setValue(g);
}
})
}
Answer
You can try a looping method to access all of the sheet tabs inside of your newSheet Spreadsheet file using the getSheets() method.
Just replace part of your script from the creation of newSheet to the last line of A1.createTextFinder with the script below:
[UPDATED]
Sample Script
const newSheet = SpreadsheetApp.openById(copy.getId());
for (currentSheet = 0; currentSheet < newSheet.getSheets().length; currentSheet++) {
const a1 = newSheet.getSheets()[currentSheet].getDataRange();
a1.createTextFinder("{{Customer}}").replaceAllWith(row[3]);
a1.createTextFinder("{{Car}}").replaceAllWith(row[1]);
a1.createTextFinder("{{Color}}").replaceAllWith(row[2]);
a1.createTextFinder("{{Delivery}}").replaceAllWith(row[5]);
}
Sample Test:
Sample copy of the newSheet file w/ 2 sheet tabs
Script test demonstration
The newSheet file that contains 2 sheet tabs:
Sheet 1
Sheet 2

Clone Googlsheet which has formulas/importranges

I would like to clone/copy a google sheet and locate it in a drive, The script i have at the moment is working for this element but the contents appear blank becuase of formulas/importranges
Please can you help with this. Current script is
function cloneGoogleSheet2() {
const destFolder = DriveApp.getFolderById("xxxxxxxxxxx");
const file = DriveApp.getFileById("xxxxxxxxxxxxxxx").makeCopy("xxxxxxxxx", destFolder);
const ss = SpreadsheetApp.openById(file.getId());
const sheets = ss.getSheets();
sheets.forEach(sh=>{
let rng = sh.getDataRange();
rng.copyTo(rng, {contentsOnly:true});
SpreadsheetApp.flush();
});
}
Reference to similar question below
Copy a spreadsheet file to Google Drive and replace all the formulas with values
Explanation:
Unfortunately:
importranges can not be allowed programmatically. So you need to set get the values from the source spreadsheet and paste them to the newly created (target) spreadsheet.
copyTo can not be used between two different spreadsheets, so you can use getValues and setValues instead.
The logic is to iterate over the source sheets and for every sheet get values and copy them to the corresponding target sheets.
Solution:
function cloneGoogleSheet2() {
const destFolder = DriveApp.getFolderById("folder_id");
const source_id = "spreadsheet_id_to_copy";
const source_ss = SpreadsheetApp.openById(source_id);
const file = DriveApp.getFileById(source_id).makeCopy("new_file", destFolder);
const target_ss = SpreadsheetApp.openById(file.getId());
const source_sheets = source_ss.getSheets();
const target_sheets = target_ss.getSheets();
source_sheets.forEach((sh,i)=>{
let values = sh.getDataRange().getValues();
target_sheets[i].getDataRange().setValues(values);
SpreadsheetApp.flush();
})
}

HOW TO USE: Global Array in Function with Loop/While (JavaScript/GAS)

I would like to use a global array / variable in my function. The function should be executed as long as IDS are in the array.
In the variable "var files = [...];" there are for example two
IDS, depending on how many files are in the folder.
var files = ['16EdsAx', '16wQxxIc'];
var files = [];
function getListOfId(){
var folderId = "11tjb_odTJ2E_ez";
var filesN = DriveApp.getFolderById(folderId).getFiles();
while (filesN.hasNext()) files.push(filesN.next().getId());
//console.log(files);
}
Don't be intimidated, these two functions only read the DOCs documents
and write them into the corresponding cell.
function getDocItems(docID, identifier){
const body = DocumentApp.openById("13TlciLOZV").getBody(); // >>> The IDS from the array should be used here <<<<
const docText = body.getText();
//Check if search characters are to be included.
let startLen = identifier.start_include ? 0 : identifier.start.length;
let endLen = identifier.end_include ? 0 : identifier.end.length;
//Set up the reference loop
let textStart = 0;
let doc = docText;
let docList = [];
//Loop through text grab the identifier items. Start loop from last set of end identfiers.
while(textStart > -1){
let textStart = doc.indexOf(identifier.start);
if(textStart === -1){
break;
}else{
let textEnd = doc.indexOf(identifier.end) + identifier.end.length;
let word = doc.substring(textStart,textEnd);
doc = doc.substring(textEnd);
docList.push(word.substring(startLen,word.length - endLen));
};
};
//return a unique set of identifiers.
return [...new Set(docList)];
};
//The chewy conversation
function runsies(){
const docID = "13TlciLOZV"; // >>> The IDS from the array should be used here <<<<
const identifier = {
start: `ISIN: `,
start_include: false,
end: `VERRECHNUNGSKONTO`,
end_include: false
};
let results = getDocItems(docID, identifier);
//var commaAdd = results.join("''");
//console.log(results);
const ss = "17a55HCwlO5uF8gkXpG";//The spreadsheet ID
const sheet = "Stock_Data";//The sheet tab name
var activeSheet = SpreadsheetApp.getActiveSheet();
let importToSpredsheet = SpreadsheetApp.openById(ss).getSheetByName(sheet);
const range = activeSheet.getRange(6,1,results.length,1);
range.setValue(results);
};
Here you can find the tutorial where I got this code from. HERE
I always used the exact docs id in the code. But now I would like to use the ids from the array from the getListOfId () function. The information from the files should all be in different cells, ideally all in column A one below the other.
So my questions are:
How can I refer to the IDS in the other two functions?
The function should be repeated until all IDS have been used and all files have been read out and entered in the spreadsheet, but how?
I believe your goal as follows.
You want to retrieve the Google Document IDs from the function of getListOfId.
In this case, the IDs returned from getListOfId are always the file IDs of Google Document.
You want to use the file IDs to docID of let results = getDocItems(docID, identifier); in the function of runsies.
You want to put the values retrieved from the function of getDocItems to the sheet of Stock_Data in the Google Spreadsheet.
Modification points:
In this case, I would like to propose the following flow.
Retrieve the file IDs from getListOfId.
In this modification, the file IDs retrieved from getListOfId are used in runsies.
Put the file IDs to getDocItems using a loop.
Put the result values to the Spreadsheet.
When I saw your script for putting values to the Spreadsheet, the values are put to the active sheet. If you want to put the values to the sheet of Stock_Data in the Google Spreadsheet of const ss = "17a55HCwlO5uF8gkXpG";, it is required to modify the script.
And also, in your script, by const range = activeSheet.getRange(6,1,results.length,1); and range.setValue(results);, the 1st element in the array of results is put the number of times of the length of results from the cell "A6". When you want to put the values from the row 6, it is required to modify the script.
When above points are reflected to your script, it becomes as follows.
Modified script:
getListOfId()
Please set your folder ID.
function getListOfId(){
var folderId = "###"; // Please set your folder ID.
var filesN = DriveApp.getFolderById(folderId).getFiles();
var files = [];
while (filesN.hasNext()) files.push(filesN.next().getId());
return files;
}
runsies()
Please set your Spreadsheet ID.
function runsies(){
const docIDs = getListOfId(); // Here, the file IDs are retrieved from `getListOfId`.
const identifier = {
start: `ISIN: `,
start_include: false,
end: `VERRECHNUNGSKONTO`,
end_include: false
};
if (docIDs.length == 0) return;
const results = docIDs.map(id => getDocItems(id, identifier)); // Here, the retrieved file IDs are used in a loop.
const ss = "###"; // Please set your Spreadsheet ID.
const sheetName = "Stock_Data"; //The sheet tab name
const sheet = SpreadsheetApp.openById(ss).getSheetByName(sheetName);
const range = sheet.getRange(sheet.getRange(6,1).isBlank() ? 6 : sheet.getLastRow() + 1,1,results.length,results[0].length);
range.setValues(results);
}
In this case, when docIDs has not file IDs, the script is stopped.
In this modified script, from your script, the retrieved values results are put from the row 6 on the sheet of Stock_Data in the Google Spreadsheet const ss = "###". When the values has already been existing from the row 6, the values are appended.
getDocItems(docID, identifier)
From:
const body = DocumentApp.openById("13TlciLOZV").getBody();
To
const body = DocumentApp.openById(docID).getBody();
Note:
Please use this modified script with enabling V8 runtime.
If above modification is not the result you expect, can you show the whole script and the detail of your goal? By this, I would like to confirm it.
References:
map()
setValues(values)

Google Sheets save the style of sheet while merging it to another sheet

I need to save the styles of the sheets when I combine them into a mainsheet. Here is the code:
function myFunction()
{
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var newSheet = activeSpreadsheet.getSheetByName("MainSheet");
if (newSheet != null) {
activeSpreadsheet.deleteSheet(newSheet);
}
newSheet = activeSpreadsheet.insertSheet();
newSheet.setName("MainSheet");
const ss = SpreadsheetApp.getActiveSpreadsheet();
const allSheets = ss.getSheets();
const allSheets_names=allSheets.map(sheet=>sheet.getSheetName())
const dataRange = "A1:M";
const checkRange = "A1:A";
const neededSheets = ["Cats", "Dogs"];
const filteredListOfSheetsNames = [];
neededSheets.forEach(function(ns){
var i = neededSheets.indexOf(ns);
filteredListOfSheetsNames[i]=[];
allSheets_names.forEach( (as,index) => {
if (as.indexOf(ns)>-1){
filteredListOfSheetsNames[i].push(as);
}
}
)
const filteredListOfSheets = filteredListOfSheetsNames[i].map(name =>ss.getSheetByName(name));
var array = [];
filteredListOfSheets.forEach(function(sheet){var values = sheet.getRange(1,1,sheet.getLastRow(),13).getValues(); array.push(values);});
array = [].concat.apply([],array);
if(array.length > 0){
newSheet.getRange(1,i*13+1, array.length, array[0].length).setValues(array);
}
}
)
}
Currently, I get all the information correctly. On one side of the mainsheet I get sheets that contain a word "dog" in them and on another side of the mainsheet I get the sheets that contain a word "cat". The issue is that the font, colors disappear after I combine all the sheets. How should I keep the styles when combining the sheets?
Here is an example of the MainSheet on how it should look like, but it should also take all of the styles from the sheets.
You can use copyTo to copy the formatting from one sheet to another. See documentation here.
Here is a minimal example based off of your script that copies the formatting to mainSheet from sheets Cats and Dogs. This script assumes that the script will be attached to the spreadsheet on which it is to operate, which you're likely already doing.
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const mainSheet = ss.getSheetByName("MainSheet");
const neededSheets = ["Cats", "Dogs"];
mainSheet.clearFormats().clear() // clear formatting and values on main sheet
for(var i=0; i<neededSheets.length; i++)
{
var sheet = ss.getSheetByName(neededSheets[i]) ;
var values = sheet.getRange(1,1,sheet.getLastRow(),13).getValues();
mainSheet.getRange(1,i*13+1, values.length, values[0].length).setValues(values);
var sourceRange = sheet.getRange(1,1,sheet.getLastRow(),13) // define the range that has the formatting you want to copy
var targetRange = mainSheet.getRange(1,i*13+1, values.length, values[0].length) // define the range that you want to copy the formatting to
sourceRange.copyTo(targetRange, {formatOnly:true}) // copy the format
}
}

Looking for one Google Script App for 4 sheet tabs to produce one json

Ok...not sure how to do this. Right now I 4 sheets and 4 scripts for each sheet producing 4 json feeds. What I am trying to experiment with is having one script that will produce 1 json that I can use in a web page and just call the type of class. They are all formatted the same with columns etc.
Here is the Google Script App code I have.
function doGet(e){
// Change Spread Sheet url
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/SpreadsheetID/edit#gid=0");
// Sheet Name, Change Sheet to whatever name you used to name your sheet
var sheet = ss.getSheetByName("Class Sheet 1");
return getClasses(sheet);
}
function getClasses(sheet){
var dataObj = {};
var dataArray = [];
// collecting data starting from 2nd Row , 1st column to last row and last column
var rows = sheet.getRange(2,1,sheet.getLastRow()-1, sheet.getLastColumn()).sort([{column: 1, ascending: true}, 1]).getValues();
for(var i = 0, l= rows.length; i<l ; i++){
var dataRow = rows[i];
var record = {};
record['Name'] = dataRow[0];
record['Note'] = dataRow[1];
record['Address'] = dataRow[2];
record['StreetAddress'] = dataRow[3];
record['City'] = dataRow[4];
record['State'] = dataRow[5];
record['ZipCode'] = dataRow[6];
record['ContactName'] = dataRow[7];
record['EMailAddress'] = dataRow[8];
record['CustomerServicePhone'] = dataRow[9];
dataArray.push(record);
}
dataObj = dataArray;
var result = JSON.stringify(dataObj);
return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}
Scratching my head on this a little bit....I'm sure its something simple and I am probably over thinking things, but any help would be appreciated.
Possible Solution:
The e object in your doGet(e) provides a way to send parameters to your script. You can access different sheets with different url parameters. You can then easily get the requested SheetName through e.parameter. Use
https://script.google.com/.../exec?sheet=ClassSheet1 //for ClassSheet1
https://script.google.com/.../exec?sheet=ClassSheet2 //for ClassSheet2
Code.gs:
function doGet(e){
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/SpreadsheetID/edit#gid=0");
var sheetName = e.parameter.sheet;
var sheet = ss.getSheetByName(sheetName);
return getClasses(sheet);
}
You can also provide UI in your web-app to select a sheet.

Categories

Resources