Google Apps Script URL being converted to text with copy row - google-apps-script

The following code copies a row from one sheet and adds it to the next free row of another sheet. However, one of the cells in the source range contains a hyperlink to a Google Drive folder. When the range is added to the bottom of the target sheet the hyperlink is stripped out leaving just the folder name in text. How can I retain the hyperlink during the copy process?
My Code:
function updateProjectLog() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName('Metadata');
var sourceRange = sourceSheet.getRange('metadataRecord');
var sourceValues = sourceRange.getValues();
var rowCount = sourceValues.length;
var columnCount = sourceValues[0].length;
var targetSheet = ss.getSheetByName('Project Log');
var lastRow = targetSheet.getLastRow();
var targetRange = targetSheet.getRange(lastRow + 1, 1, rowCount, columnCount);
targetRange.setValues(sourceValues);
}

Use RichTextValues to manage stylized text, including links:
function updateProjectLog() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = ss.getSheetByName('Metadata');
var sourceRange = sourceSheet.getRange('metadataRecord');
var sourceValues = sourceRange.getRichTextValues();
var rowCount = sourceValues.length;
var columnCount = sourceValues[0].length;
var targetSheet = ss.getSheetByName('Project Log');
var lastRow = targetSheet.getLastRow();
var targetRange = targetSheet.getRange(lastRow + 1, 1, rowCount, columnCount);
targetRange.setRichTextValues(sourceValues);
}

Related

"CELLIMAGE" text displayed in place of image upon export pdf script from Google sheets

Hi there those way cleverer than me!
I have a Google script to export a pdf from a Google sheet which works fine. However I have an image in a cell that is not displayed in the exported pdf, instead it just says "CELLIMAGE". If I manually export the pdf it displays the image correctly...
My code is:
function exportFl() {
var sheetName = "FL"
//var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
//var allsheets = ss.getSheets();
//for (var s in allsheets){
//var sheet=allsheets[s]
//var maxRows = ss.getMaxRows();
//var lastRow = ss.getLastRow();
//if (maxRows-lastRow != 0){
//ss.deleteRows(lastRow+1, maxRows-lastRow);}
var value = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange('E7').getValue();
var folderID = "1x0tBqOP07e2XIzXHgvYqAaBiu7Zd7DfV"; // Folder id to save in a folder.
var timeZone = Session.getScriptTimeZone();
date = Utilities.formatDate(new Date(), timeZone, "YYMMdd");
var pdfName = value+"_FSL Conformance_"+ date;
var sourceSpreadsheet = SpreadsheetApp.getActive();
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var folder = DriveApp.getFolderById(folderID);
//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];
//repace 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
// --- I added below script.
var r = destSheet.getDataRange();
var startRow = r.getNumRows() + 1;
var number = destSheet.getMaxRows() - startRow + 1;
if (number > 0) destSheet.deleteRows(startRow, number);
SpreadsheetApp.flush(); // This might not be required to be used.
// ---
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
//Delete the temporary sheet
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
Anyone got any ideas??
Thanks
It seems that in your script, the cells are overwritten by destRange.setValues(sourcevalues);. I thought that this might be the reason of your issue. And, in your script, the values have already been copied by var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder)). So in this case, how about the following modification?
In this modification, I used the following flow.
Copy the 1st tab.
Overwrite the data to the copied sheet.
Copy the images in the cells to the copied sheet.
Delete the temporal sheet.
When this flow is reflected to your script, it becomes as follows.
Modified script:
From:
var destSheet = destSpreadsheet.getSheets()[0];
//repace 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);
To:
var tempSheet = destSpreadsheet.getSheets()[0];
// 1. Copy the 1st tab.
var destSheet = tempSheet.copyTo(destSpreadsheet);
// 2. Overwrite the data to the copied sheet.
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);
// 3. Copy the images in the cells to the copied sheet.
sourcevalues.forEach((r, i) => {
r.forEach((c, j) => {
if (c.toString() == "CellImage") {
tempSheet.getRange(i + 1, j + 1).copyTo(destSheet.getRange(i + 1, j + 1), {contentsOnly: true}); // Modified
}
});
});
// 4. Delete the temporal sheet.
destSpreadsheet.deleteSheet(tempSheet);
References:
copyTo(spreadsheet) of Class Sheet
copyTo(destination) of Class Range

how to fix my copy data range into other files in app script google

i have to copy my sheet from file1 (16aWONG-TyHYxYFYqfDI7Pw2PVuNvDQ0cnFoIv_SDA4U) into file2 (1zIeqvQuC7RlXy9SB--SaNaEXKT399NvffM3F3nfAXGs)
i have this script, but it didnt work, i don't know where to put fromfile
function getdata() {
var files = DriveApp.getFileById("1zIeqvQuC7RlXy9SB--SaNaEXKT399NvffM3F3nfAXGs").getFiles()
while (files.hasNext()) {
var file = files.next();
var shoot = SpreadsheetApp.openById(file.getId());
var sourcesheet = SpreadsheetApp.getActive().getSheetByName("BahanMix");
var sourcerange = sourcesheet.getRange('A:D');
var sourcevalues = sourcerange.getValues();
var destsheet = shoot.getSheetByName('Sheet23');
var destrange = destsheet.getRange('A:D');
destrange.setValues(sourcevalues);
}
}
I would stick with the spreadsheet app versus using drive as your initial code operates on. I think you can get what you want with this below code. I included a check to ensure the row count is the same.
function getDate() {
var fromFile = SpreadsheetApp.openById("16aWONG-TyHYxYFYqfDI7Pw2PVuNvDQ0cnFoIv_SDA4U");
var targetFile = SpreadsheetApp.openById("1zIeqvQuC7RlXy9SB--SaNaEXKT399NvffM3F3nfAXGs");
var sourcesheet = fromFile.getSheetByName("BahanMix");
var sourcerange = sourcesheet.getRange('A:D');
var sourcevalues = sourcerange.getValues();
var destsheet = targetFile.getSheetByName('Sheet23');
var destrange = destsheet.getRange('A:D');
//make sure the same number or rows exist
if (destsheet.getMaxRows()!= sourcesheet.getMaxRows()){
Browser.msgBox("Row MisMatch. Destination has " +
destsheet.getMaxRows() + " rows while source has " +
sourcesheet.getMaxRows()) + " rows."
}else{
destrange.setValues(sourcevalues);
}
}
Since you are using getActive() your script is bound to your source spreadsheet, so SpreadsheetApp can be used directly to open files.
function getdata() {
var shoot = SpreadsheetApp.openById("1zIeqvQuC7RlXy9SB--SaNaEXKT399NvffM3F3nfAXGs");
var sourcesheet = SpreadsheetApp.getActive().getSheetByName("BahanMix");
var sourcerange = sourcesheet.getRange('A:D');
var sourcevalues = sourcerange.getValues();
var destsheet = shoot.getSheetByName('Sheet23');
var destrange = destsheet.getRange('A:D');
destrange.setValues(sourcevalues);
}

Mass Edit of Cell Range in Sheets in Folder Using Script

I have used this script in the past to edit a cell or range of cells in a set of spreadsheets in a specific folder (using a source file), but when I run the script it does not work. In fact, instead of copying the range from the source sheet it clears out existing data in the destination sheets.
Here is script I have been using:
var files = DriveApp.getFolderById("1NNHFL6fMFz-LwJ4tZrvTN92foXhf7VS8").getFiles()
while (files.hasNext()) {
var file = files.next();
var shoot = SpreadsheetApp.openById(file.getId());
var sourcesheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var sourcerange = sourcesheet.getRange('A:A');
var sourcevalues = sourcerange.getFormulas();
var destsheet = shoot.getSheetByName('Sheet1');
var destrange = destsheet.getRange('A:A');
destrange.setValues(sourcevalues);
}
}
Here is a link to the folder I have been testing this in.
Your script works fine if you change setValues() to setFormulas (if you need formulas):
function myFunction() {
var files = DriveApp.getFolderById("1NNHFL6fMFz-LwJ4tZrvTN92foXhf7VS8").getFiles()
while (files.hasNext()) {
var file = files.next();
var shoot = SpreadsheetApp.openById(file.getId());
var sourcesheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var sourcerange = sourcesheet.getRange('A:A');
var sourcevalues = sourcerange.getFormulas();
var destsheet = shoot.getSheetByName('Sheet1');
var destrange = destsheet.getRange('A:A');
destrange.setFormulas(sourcevalues); // <------------- HERE
}
}
Try this:
function myfunc() {
var files = DriveApp.getFolderById("1NNHFL6fMFz-LwJ4tZrvTN92foXhf7VS8").getFiles()
const ss=SpreadsheetApp.getActive();
var sourcesheet = ss.getSheetByName("Sheet1");
var sourcerange = sourcesheet.getRange(1,1,sourcesheet.getLastRow(),1);
var sourcevalues = sourcerange.getFormulas();
while (files.hasNext()) {
var file = files.next();
var shoot = SpreadsheetApp.openById(file.getId());
var destsheet = shoot.getSheetByName('Sheet1');
var destrange = destsheet.getRange(1,1,sourcesheet.getLastRow(),1);
destrange.setFormulas(sourcevalues);
}
}

How Can I Change My Range to Include Merged Cells?

I am trying to copy and paste "A4:J4" and "A5:H5" but I am getting an error because A5 is merged. Also "STAGE 3" only pastes in "G4" in Sheet2. How can I copy and paste this data to Sheet2 with merged cells?
function hi()
{
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
var yourRange = sheet.getRange("A4");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var destSheet = ss.getSheetByName('Sheet2');
var yourLastColumn=sheet.getRange("A4:4").getLastColumn();
var range = ss.getRangeByName("A4");
var yourLastRange=sheet.getRange("A4").offset(0, yourLastColumn-1);
var rsltRange1 = yourLastRange.getNextDataCell(SpreadsheetApp.Direction.PREVIOUS);
var rsltRange2 = sheet.getRange("A4:" + rsltRange1.getA1Notation());
if (rsltRange2.isPartOfMerge()) {
var rangeTest = rsltRange2.getMergedRanges()[0];
} else {
}
Logger.log(rangeTest.getA1Notation());
var destRange = destSheet.getRange("A4");
rsltRange2.copyTo(destRange, {contentsOnly: false});
}
Here is a simplified version of your code that should copy your range correctly no matter if the range is merged or not:
function hi(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var destSheet = ss.getSheetByName('Sheet2');
var startColumn=1;
var startRow=4;
var numRows=2;
var numColumns=sheet.getLastColumn()-startColumn+1;
var range=sheet.getRange(startRow, startColumn, numRows, numColumns);
var destRange = destSheet.getRange("A4");
range.copyTo(destRange);
}

How to show spreadsheet name in Logger

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());
}