How to show spreadsheet name in Logger - google-apps-script

I am trying to get a chart from spreadsheet A. I take this into a Chart object, and try to put it back in spreadsheet B.
I always get an 'unknown sheetname' error. I have been trying to put new ranges in the new chart, as you can see in the code. When I do a Logger.log(newrange.getSheet()) I indeed get Sheet instead of SHEETNAME, like the chart builder messes with the sheetnames.
What is happening?
function updateCharts() {
var ss = SpreadsheetApp.openById("ID");
var sheet = ss.getSheetByName("SHEETNAME");
var charts = sheet.getCharts();
var ss2 = SpreadsheetApp.openById("NEW ID");
var sheet2 = ss2.getSheetByName("SHEETNAME");
for (var c=0; c<charts.length; c++) {
var chart = charts[c];
var ranges = chart.getRanges();
var type = chart.getType();
var info = chart.getOptions();
var builder = chart.modify();
var range = ranges[0];
builder.removeRange(range);
var startRow = range.getRow();
var startCol = range.getColumn();
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
var newrange = ss2.getSheetByName("statistiek").getRange(startRow, startCol, numRows, numCols);
Logger.log(newrange.getSheet());
builder.addRange(newrange);
var title = chart.getOptions().get('title')
builder.setOption('title', title + " " + p);
var newchart = builder.build();
ss2.getSheetByName("statistiek").insertChart(newchart);
}
}

Logger.log() requires a string, but you're feeding it an object with newrange.getSheet(). Try this instead, if you want the sheet's name:
Logger.log(newrange.getSheet().getName())
To see the names of all sheets in a spreadsheet, try:
var ss = SpreadsheetApp.openById("ID");
var allSheets = ss.getSheets();
for (i in allSheets) {
Logger.log("Sheet " + i + " is named " + allSheets[i].getName());
}

Related

Copy Row from one Sheet to another sheet which is linked in the row

I have previously been able to copy rows from one Spreadsheet to another, however what I am trying to do now is copy a row to a specific spreadsheet that is linked on the same row and I can't seem to work it out.
I have around 500 rows of names with data (I cannot share a sheet as my firms Google does not allow for sharing externally but I have a screenshot of dummy data below). I used a formula to find the Unique names and then created a Google Sheet for each person and linked the Sheet back to the master data.
Master Data Sheet (tab is called Sheet1)
I am looking for a script that will work through the sheet, copying the rows to the link that is on the same row but I just can't figure it out - the following script does not work but I am at a loss so any help would be appreciated.
Apologies if I haven't explained myself very well!!
function copyTo(){
var sSheet = SpreadsheetApp.getActiveSpreadsheet();
var srcSheet = sSheet.getSheetByName("Sheet1");
var data = srcSheet.getDataRange().getValues();
for(var i = 1; i < data.length; i++) {
var row = data[i];
var link = row[3];
var id = row[4];
var complete = row[5];
var COMPLETE = "Complete"
if(link !== "" && complete !== "Complete"){
var srcRange = srcSheet.getRange("A" + i + ":C" + i);
var linkID = id.toString()
var tarSS = DriveApp.getFileById(linkID);
var tarSheet = tarSS.getSheetbyName("Sheet1");
var tarRow = tarSheet.getLastRow();
//tarSheet.insertRowAfter(tarRow);
var tarRange = tarSheet.getRange("A" + (tarRow+1) + ":C" + (tarRow+1));
srcRange.copyTo(tarRange);
srcSheet.getRange(i+1,6).setValue(COMPLETE)
}
}};
Try this:
function copyTo() {
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName("Sheet1");
var vs = sh.getDataRange().getValues();
for (var i = 1; i < vs.length; i++) {
var row = vs[i];
var link = row[3];
var id = row[4];
var complete = row[5];
var COMPLETE = "Complete"
if (link !== "" && complete !== "Complete") {
var rg = sh.getRange("A" + i + ":C" + i);
var linkID = id.toString()
var tarSS = SpreadsheetApp.openById(linkID);
var tarSheet = tarSS.getSheetbyName("Sheet1");
var tarRow = tarSheet.getLastRow();
var tarRange = tarSheet.getRange("A" + (tarRow + 1) + ":C" + (tarRow + 1));
rg.copyTo(tarRange);
sh.getRange(i + 1, 6).setValue(COMPLETE)
}
}
};
As much as I understand you question here is the script which will work for you exactly you want .
This will copy data from sheet you want and then create a new spreadsheet and paste into that sheet then link will show of this in same sheet from data copied
Let me know how this worked .
Code.gs
const sendDataToSheet = () => {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const ws = ss.getSheetByName(''paste here your sheet name'')
const newSheet = SpreadsheetApp.create("give new sheet name here")
ws.copyTo(newSheet).setName("Copied Data")
const sheetURL = newSheet.getUrl()
ws.insertRowBefore(1)
ws.getRange(1,1).setValue(sheetURL)
}

Using Google Script I want to add a timestamp to each row of the result

I want to add a timestamp to each row of the result. I have attempted to add a separate timestamp script on edit but that is not working. Below is the code I am using.
function importCSVFromGmail() {
var threads = GmailApp.search("Gmail Search");
var message = threads[0].getMessages();
var attachment = message[message.length - 1].getAttachments()[1];
var sheet = SpreadsheetApp.openById('SHEET ID');
var tab = sheet.getSheetByName('Data');
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
var startRow = sheet.getLastRow();
var dataRange = tab.getRange(startRow,1,csvData.length,
csvData[0].length).setValues(csvData);
}
function importCSVFromGmail() {
var threads = GmailApp.search("Gmail Search");
var message = threads[0].getMessages();
var attachment = message[message.length - 1].getAttachments()[1];
var sheet = SpreadsheetApp.openById('SHEET ID');
var tab = sheet.getSheetByName('Data');
var csvData = Utilities.parseCsv(attachment.getDataAsString(), ",");
let o = csvData.map(r => {
let x = r.slice();
x.push(new Date());
return x;
}})
var startRow = sheet.getLastRow();
tab.getRange(startRow, 1, o.length, o[0].length).setValues(o);
}

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.

How can I check for duplicates in a list before copying an item to a new sheet?

I want to copy data from one sheet (Sheet1) to another (Sheet2). Before the data copies over, I want to check in column A on both sheets for duplicates, so that only the non-duplicates are copied over. I am specifically having trouble writing the IF statement and FOR loop to do this.
I have the following code and pictures below:
function Demo() {
var Sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var Sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var ColumntoSearch = 1;
var LastRow = Sheet1.getLastRow();
var LastRow2 = Sheet2.getLastRow();
//Gets range and values to compare for duplicates
var Range = Sheet1.getRange(2, ColumntoSearch,LastRow, 1);
var Values = Range.getValues();
logger.log("The Values to transfer over are: " + Values);
//Gets range and values to compare duplicates to
var Range2 = Sheet2.getRange(5, 1, LastRow2, 1)
var Values2 = Range2.getValues();
logger.log("The Values to Search are: " + Values2);
//Sets the amount of data to copy over
var NumberofColumns = 2;
var NumberofRows = 1;
var DestRow = Sheet2.getLastRow()+1;
//Compares all the material codes for duplicates and copies over the non-duplicates
var dt=new Date();
var dv=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();
var d=0;
for(var i=0;i<Values.length;i++) {
if((???????)) {
var RangetoCopy=Sheet1.getRange(i-d+5,1,NumberofRows,NumberofColumns);
var DestRange=Sheet2.getRange(Sheet2.getLastRow()+1,1,NumberofRows,NumberofColumns);
RangetoCopy.copyTo(DestRange);
d++;}}
Logger.log("Next Destination Row: " + DestRow);
}
Image1
Try something like this:
function checkForDupesAndCopy() {
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName("Sheet1");
var sh2=ss.getSheetByName("Sheet2");
var ColumntoSearch = 1;
var rg1=sh1.getRange(2,1,sh1.getLastRow()-1,1); //cola sheet1
var vA1=rg1.getValues();
var rg2=sh2.getRange(5,1,sh2.getLastRow()-4,1)
var vA2=rg2.getValues();
var vlist=vA2.map(function(r){return r[0];});
var dt=new Date();
var dv=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()).valueOf();
for(var i=0;i<vA1.length;i++) {
if(vlist.indexOf(vA1[i][0])==-1) {
var RangetoCopy=sh1.getRange(i+2,1,1,2);
var DestRange=sh2.getRange(sh2.getLastRow()+1,1,1,2);
RangetoCopy.copyTo(DestRange);
}
}
}
Note: I tested this on some data of my own.

Preserve formula references when printing a single Google Sheets sheet to PDF

I want to accomplish the following:
Make a menu with a print to PDF button.
Have that button export a PDF to with the same name and same destination as the google sheet.
This works well, but the script I found I need to change, because most people print to PDF by making a temporary copy of the sheet, printing, and finally deleting the temporary copy.
I have references from other sheets in my original document that ends up printed as #REF! values because only the one sheet gets copied and printed, not my whole document.
How can i make this process include baking the formulas as text?
CODE FOR PRINTING:
function onOpen() {
var submenu = [{name: "Save PDF", functionName: "generatePdf"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Export', submenu);
}
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as sheetName.
var pdfName = sheetName;
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
}
else {
folder = DriveApp.getRootFolder();
}
// Copy whole spreadsheet.
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))
// Delete redundant sheets.
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != sheetName){
destSpreadsheet.deleteSheet(sheets[i]);
}
}
var destSheet = destSpreadsheet.getSheets()[0];
// Replace cell values with text (to avoid broken references).
var sourceRange = sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns());
var sourcevalues = sourceRange.getValues();
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
destRange.setValues(sourcevalues);
// Save to pdf.
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
// Delete the temporary sheet.
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
CODE FOR CONVERTING FORMULAS TO TEXT:
function formulasAsText() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var k = 0; k < sheets.length; k++) {
var range = sheets[k].getDataRange();
var values = range.getValues();
var formulas = range.getFormulas();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[0].length; j++) {
values[i][j] = formulas[i][j] ? "'" + formulas[i][j] : values[i][j];
}
}
range.setValues(values);
}
}
To maintain formula references, you need to modify the formulasAsText() function to accept an input, and also not worry about writing a formula if one is found. This input could be a spreadsheet ID - i.e. the id of the temporary copy - or it could be an array of Sheet objects.
Once you have made these two modifications, you would call the function prior to deleting the non-desired sheets in the temporary copy:
/**
* #param Sheet[] wbSheets An array of Sheets to operate on.
* #param String toPreserve The name of the sheet which should be preserved.
*/
function preserveFormulas(wbSheets, toPreserve) {
if(!wbSheets || !wbSheets.length || !toPreserve)
throw new Error("Missing arguments.");
wbSheets.forEach(function (sheet) {
if ( sheet.getName() === toPreserve ) {
var range = sheet.getDataRange();
// Serialize the cell's current value, be it static or derived from a formula.
range.setValues(range.getValues());
}
});
}
Finished my script. Here is what i ended up with.
function onOpen() {
var submenu = [{name:"Save PDF", functionName:"generatePdf"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Export', submenu);
}
function hideSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("sheet1");
var sheet2 = ss.getSheetByName("PRINT SHEET");
var sheet3 = ss.getSheetByName("sheet3");
var sheet4 = ss.getSheetByName("sheet4");
var sheet5 = ss.getSheetByName("sheet5");
var sheet6 = ss.getSheetByName("sheet6");
var sheet7 = ss.getSheetByName("sheet7");
sheet1.hideSheet();
sheet3.hideSheet();
sheet4.hideSheet();
sheet5.hideSheet();
sheet6.hideSheet();
sheet7.hideSheet();
}
function showSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("sheet1");
var sheet2 = ss.getSheetByName("PRINT SHEET");
var sheet3 = ss.getSheetByName("sheet3");
var sheet4 = ss.getSheetByName("sheet4");
var sheet5 = ss.getSheetByName("sheet5");
var sheet6 = ss.getSheetByName("sheet6");
var sheet7 = ss.getSheetByName("sheet7");
sheet1.showSheet();
sheet3.showSheet();
sheet4.showSheet();
sheet5.showSheet();
sheet6.showSheet();
sheet7.showSheet();
}
function generatePdf() {
// Get active spreadsheet.
var sourceSpreadsheet = SpreadsheetApp.getActive();
// Get active sheet.
var sheets = sourceSpreadsheet.getSheets();
var sheetName = sourceSpreadsheet.getActiveSheet().getName();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
// Set the output filename as BID and number (from cell C4).
var pdfName = "BID " + sheets[0].getRange("C4").getValue() + ".pdf";
var ui = SpreadsheetApp.getUi();
// Get folder containing spreadsheet to save pdf in.
var parents = DriveApp.getFileById(sourceSpreadsheet.getId()).getParents();
if (parents.hasNext()) {
var folder = parents.next();
}
else {
folder = DriveApp.getRootFolder();
}
hideSheets();
// Save to pdf.
var theBlob = sourceSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
showSheets();
ui.alert('Export finished');
}
Thanks.