folder.getFiles is not a function error in Trigger - google-apps-script

When I run my function in Apps Script its working fine but when I add it in a trigger this error always occurs in first run.
TypeError: folder.getFiles is not a function
This is the code. I use this code to get all files in all folders and subfolders.
var level=0;
function getFnF(folder) {
var folder= folder || DriveApp.getFolderById('root folder ID');
var ss=SpreadsheetApp.openById('google sheet ID');
var sh=ss.getSheetByName('List');
var files=folder.getFiles();
while(files.hasNext()) {
var file=files.next();
var fileid = file.getId();
var TimeStamp = Utilities.formatDate(new Date(), "GMT+8", "MMMM dd, yyyy HH:mm:ss")
var filesize = file.getSize()/ 1024 / 1024;
var lastrow = sh.getLastRow();
var filename =file.getName();
sh.appendRow([TimeStamp,lastrow,filename,file.getName(),filesize.toFixed(2),fileid);
Logger.log('Item added in list: ['+ lastrow+"] " + filename);
}
var subfolders=folder.getFolders()
while(subfolders.hasNext()) {
var subfolder=subfolders.next();
//subfolders only
level++;
getFnF(subfolder);
}
level--;
}
I hope you can help me.

From When I run my function in apps script its working fine but when I add it in a trigger this error always occurs in first run., I'm not sure about the kind of trigger. But when the function is run by a trigger, the event object is given to the 1st argument. So, in this case, how about the following modification?
Modified script:
var level = 0;
function getFnF(e, folder = DriveApp.getFolderById('root folder ID')) {
var ss = SpreadsheetApp.openById('google sheet ID');
var sh = ss.getSheetByName('Sheet1');
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
var fileid = file.getId();
var TimeStamp = Utilities.formatDate(new Date(), "GMT+8", "MMMM dd, yyyy HH:mm:ss")
var filesize = file.getSize() / 1024 / 1024;
var lastrow = sh.getLastRow();
var filename = file.getName();
sh.appendRow([TimeStamp, lastrow, filename, file.getName(), filesize.toFixed(2), fileid]);
Logger.log('Item added in list: [' + lastrow + "] " + filename);
}
var subfolders = folder.getFolders()
while (subfolders.hasNext()) {
var subfolder = subfolders.next();
//subfolders only
level++;
getFnF(e, subfolder);
}
level--;
}
By this modification, when the function getFnF by a trigger, the function is run as the initial value of folder of DriveApp.getFolderById('root folder ID').
By the way, when you want to run this function from another function instead of the trigger, please call this as getFnF("dummy", folder).

Related

Google Sheet: Replace file with the same name

I'm currently generating a PDF file from an active sheet. Is there a way to overwrite or replace the file in the google drive without putting it to trash? I have this code that I saw online.
if (files.hasNext()) {
files.next().setTrashed(true);
}
Am I using the code right or there is another way for me to do it?
I used that code on the function below.
function _exportBlob(blob, fileName) {
var timeZone = Session.getScriptTimeZone();
var date = Utilities.formatDate(new Date(), timeZone, "yyyy");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var fileName = "FORM137 - " + ss.getRange("REPORT CARD!D12").getValue() + " - ARCS" + date;
var ssID = ss.getId();
var ssFile = DriveApp.getFileById(ssID);
blob = blob.setName(fileName)
var parentFolder = DriveApp.getFileById(ss.getId()).getParents().next();
var subFolder = parentFolder.getFoldersByName("CARDS").next();
var files = subFolder.getFilesByName(getFilename());
if (files.hasNext()) {
files.next().setTrashed(true);
}
var pdfFile = subFolder.createFile(blob);
if (pdfFile) {
const htmlOutput = HtmlService
.createHtmlOutput('<p>Click to open ' + fileName + '</p>')
.setWidth(300)
.setHeight(80)
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Export Successful')
}
}
Here's the getFilename function:
function getFilename() {
var ss = SpreadsheetApp.getActive();
var filename = "FORM137 - " + ss.getRange("REPORT CARD!D12").getValue() + " - ARCS" + date;
return filename;
}
I believe your goal as follows.
You want to overwrite blob to the existing file of getFilename().
In this case, I would like to propose to use the method of "Files: update" in Drive API.
Before you use this script, please enable Drive API at Advanced Google services.
From:
var files = subFolder.getFilesByName(getFilename());
if (files.hasNext()) {
files.next().setTrashed(true);
}
var pdfFile = subFolder.createFile(blob);
To:
var files = subFolder.getFilesByName(getFilename());
var pdfFile = files.hasNext() ? DriveApp.getFileById(Drive.Files.update({}, files.next().getId(), blob).id) : subFolder.createFile(blob);
In this modification, when the file of getFilename() is not existing, a new file is created.
Reference:
Files: update

accessing spreadsheet by ID

I am using google Apps script.
I need to access some information in the spreadsheet.
I navigate to the file and find its ID.
However, the function
var fileID = file.getId()
var activityName = Sheets.Spreadsheets.Values.get (fileID,'B1:B4'); doesn't seem to accept the ID, even thought the ID is correct as I logged it and checked.
function getTheInformation() {
//navigate to the correct folder
var dApp = DriveApp;
var folderIter = dApp.getFoldersByName("scriptFolder");
var folder = folderIter.next();
//reality check
Logger.log(folder);
var filesIter = folder.getFiles();
var i = 1;
//cycle through the files
while (filesIter.hasNext())
{
var file = filesIter.next();
var fileID = file.getId()
var fileName = file.getName();
//here the code breaks
var activityName = Sheets.Spreadsheets.Values.get (fileID,'B1:B4');
i++;
Logger.log(fileName + " file ID " + fileID);
}
}
This worked for me:
function getTheInformation() {
var dApp = DriveApp;
var folderIter = dApp.getFoldersByName("Questions");
var folder = folderIter.next();
var filesIter = folder.getFiles();
while (filesIter.hasNext()) {
var file = filesIter.next();
var fileID = file.getId()
var fileName = file.getName();
if(fileName=='StackOverflow1') {
var values = Sheets.Spreadsheets.Values.get (fileID,'Sheet1!B1:B4')
Logger.log(values);
}
}
}
Things I did a little different: I added the sheet name to the range and I also checked for the correct file name.

How do I to delete/trash/remove a csv file if exists

I'm trying to create an export to csv apps script but it will not delete existing csv files sitting in the same folder. I would like to either trash them or overwrite them.
Here's the code I've already tried
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
// create a folder from the name of the spreadsheet
// var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_' + new Date().getTime());
// var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_');
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
var file = DriveApp.getFileById(ss.getId());
var folder = file.getParents();
folder = folder.next();
// loop through files and delete ones with existing name
var existingfiles = folder.getFiles()
for (var j = 0 ; j<existingfiles.length;j++){
var existingfile = existingfiles[j].next()
if (existingfile.getName()!=ss.getName()){
//to delete
//existingfile.setTrashed(true);
folder.removeFile(existingfile);
}
}
//create new file
folder.createFile(fileName, csvFile);
}
}
I'd expect all files that don't share the same name as the spreadsheet in that folder to get removed, then a csv for each tab to get created. Instead, I get duplicates of each csv file.
Thanks a lot for you help. The while loop helped a bunch. Here's what worked for me in the end.
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var file = DriveApp.getFileById(ss.getId());
var folder = file.getParents();
folder = folder.next();
// loop through files and delete ones with existing name
var xfiles=folder.getFiles();
while(xfiles.hasNext()) {
var fi=xfiles.next();
if(fi.getMimeType()!=MimeType.GOOGLE_SHEETS){fi.setTrashed(true);}
}
// create new csv files
for (var i = 0 ; i < sheets.length ; i++) {
var sheet = sheets[i];
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
//create new file
folder.createFile(fileName, csvFile);
}
};
Try this:
function trashOthers() {
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
var fldr=DriveApp.getFileById(ss.getId()).getParents();
var n=0;
while(fldr.hasNext()) {
var folder=fldr.next();
n++;
}
if(n>1){throw('More than one Folder');}
for (var i=0;i<shts.length;i++) {
var sh=shts[i];
var fileName=sh.getName() + ".csv";
var csvFile=convertRangeToCsvFile_(fileName, sh);
var xfiles=folder.getFiles();
while(xfiles.hasNext()) {
xfiles.next().setTrashed(true);
}
folder.createFile(fileName, csvFile);
}
}
Perhaps this is better:
function deleteOthers() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var shts=ss.getSheets();
var fldr=DriveApp.getFileById(ss.getId()).getParents();
var n=0;
while(fldr.hasNext()) {
var folder=fldr.next();
n++;
}
if(n>1){throw('More than one Folder');}
for (var i=0;i<shts.length;i++) {
var sh=shts[i];
var fileName=sh.getName() + ".csv";
var csvFile=convertRangeToCsvFile_(fileName, sh);
var xfiles=folder.getFiles();
while(xfiles.hasNext()) {
var fi=xfiles.next();
if(fi.getMimeType()!=MimeType.GOOGLE_SHEETS){fi.setTrashed(true);}
}
folder.createFile(fileName, csvFile);
}
}
I used deleteOthers() and trashothers() both are deleting the google form which writes data into csv

How to loop data and print each iteration to PDF in a defined Google Drive folder

I'm a novice at GAS, so please bear with me.
I'd like to create a script for a Google Sheet that will loop through a series of values, pause at each value, and print a specific tab from the sheet to a defined location in Google Drive (creating a new folder with a date within the parent folder). Below is what I have so far, which achieves looping and printing, but I can't figure out how to get it to save the PDF files to a specific folder. Grateful for any help! Thank you.
Link to dummy spreadsheet with script here, and target Google Drive folder here.
function loop() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('Validation');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('Validation').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('Loadout');
var tab = ss.getSheetByName('Loadout');
var formattedDate = Utilities.formatDate(new Date(), "GMT+5", "yyyy-MM-dd hh:mm");
//Create Folder for PDFs
var fld = DriveApp.createFolder(formattedDate);
fld.addFile(DriveApp.getFileById(ss.getId()));
for (var i = 0; i < inputs.length; i++) {
sheet2.getRange('A1').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(5000);
//Print PDFs
var name = tab.getRange(1, 1).getValue();
fld.createFile(ss.getAs('application/pdf')).setName(name);
}
DriveApp.getRootFolder().removeFile(DriveApp.getFileById(ss.getId()));
}
You want to create PDF files to "target Google Drive folder". https://drive.google.com/drive/u/1/folders/1QmjXLyssyCGU16ApLQ4Anj_kir0uuQS8
If my understanding is correct, how about this modification?
Modification points:
Retrieve the target folder using DriveApp.getFolderById().
When PDF file is created, it creates the file to the target folder.
Modified script:
function loop() {
var targetFolderId = "1QmjXLyssyCGU16ApLQ4Anj_kir0uuQS8"; // Added
var targetFolder = DriveApp.getFolderById(targetFolderId); // Added
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('Validation');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('Validation').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('Loadout');
var tab = ss.getSheetByName('Loadout');
// var formattedDate = Utilities.formatDate(new Date(), "GMT+5", "yyyy-MM-dd hh:mm"); // Removed
//Create Folder for PDFs
// var fld = DriveApp.createFolder(formattedDate); // Removed
// fld.addFile(DriveApp.getFileById(ss.getId())); // Removed
for (var i = 0; i < inputs.length; i++) {
sheet2.getRange('A1').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(5000);
//Print PDFs
var name = tab.getRange(1, 1).getValue();
targetFolder.createFile(ss.getAs('application/pdf')).setName(name); // Modified
}
// DriveApp.getRootFolder().removeFile(DriveApp.getFileById(ss.getId())); // Removed
}
Note:
In your script, the active spreadsheet is also moved to a created new folder. About this, how do you want to do?
References:
getFolderById(id)
If I misunderstand your question, please tell me. I would like to modify it.
Edit:
When you run the script, at first, you want to create new folder in the target folder. Then, you want to create PDF files in the created folder.
About the active spreadsheet, do nothing.
I understood like above. If my understanding is correct, how about this modification?
Modified script:
function loop() {
var targetFolderId = "1QmjXLyssyCGU16ApLQ4Anj_kir0uuQS8"; // Added
var targetFolder = DriveApp.getFolderById(targetFolderId); // Added
var ss = SpreadsheetApp.getActiveSpreadsheet();
var validation_sheet = ss.getSheetByName('Validation');
var lastRow = validation_sheet.getLastRow();
var inputs = ss.getSheetByName('Validation').getRange('A2:A'+lastRow).getValues();
var sheet2 = ss.getSheetByName('Loadout');
var tab = ss.getSheetByName('Loadout');
var formattedDate = Utilities.formatDate(new Date(), "GMT+5", "yyyy-MM-dd hh:mm");
//Create Folder for PDFs
var fld = targetFolder.createFolder(formattedDate); // Modified
// fld.addFile(DriveApp.getFileById(ss.getId())); // Removed
for (var i = 0; i < inputs.length; i++) {
sheet2.getRange('A1').setValue(inputs[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(5000);
//Print PDFs
var name = tab.getRange(1, 1).getValue();
fld.createFile(ss.getAs('application/pdf')).setName(name); // Modified
}
// DriveApp.getRootFolder().removeFile(DriveApp.getFileById(ss.getId())); // Removed
}

Using google script to import .csv files into an existing google sheet. Formatting issues.

Is there a way to not duplicate the headers when the new .csv files are imported from my one drive folder into the existing google sheet? I want the .csv files to be added to the existing sheet in sequential order without adding the headers...example - like row 2 and 19 show. Also, sequential to make the dates go in order in column A. Another question I had was, do you know what happened in line 10? I have deleted and re entered the new data in and every time that happens. This is my script I have now. This is a shareable link to the sheet and what it looks like. https://docs.google.com/spreadsheets/d/1f9HEwikMxm5sJzzRh_-etBxXzL0NpK47i9LtoZVCv_0/edit?usp=sharing This is the script I have right now.
function appendingCSV() {
var ss=SpreadsheetApp.getActiveSpreadsheet()
var sht=ss.getActiveSheet();
var drng = sht.getDataRange();
var lastRow = drng.getLastRow();
var data = loadFiles();
var dataA =Utilities.parseCsv(data);
if(dataA.length>0)
{
var rng = sht.getRange(lastRow + 1, 1, dataA.length, dataA[0].length);
rng.setValues(dataA);
}
else
{
SpreadsheetApp.getUi().alert('No Data Returned from LoadFiles');
}
}
function loadFiles(folderID)
{
var folderID = (typeof(folderID) !== 'undefined')? folderID :
'0B8m9xkDP_TJxUUlueHhXOWJMbjg';
var fldr = DriveApp.getFolderById(folderID);
var files = fldr.getFiles();
var s='';
var re = /^.*\.csv$/i;
while (files.hasNext())
{
var file = files.next();
var filename = file.getName();
if(filename.match(re))
{
s += file.getBlob().getDataAsString() + '\n';
file.setName(filename.slice(0,-3) + 'old');
}
}
return s;
}
function createTimeDrivenTriggers() {
// Trigger every Friday at 09:00.
ScriptApp.newTrigger('myFunction')
.timeBased()
.onWeekDay(ScriptApp.WeekDay.FRIDAY)
.atHour(9)
.create();
}
In your loadFiles() script. Try changing it to something like this.
function loadFiles(folderID)
{
//var folderID = (typeof(folderID) !== 'undefined')? folderID : 'Your_folder_id';
var folderID = (typeof(folderID) !== 'undefined')? folderID : 'Your_folder_id';
var fldr = DriveApp.getFolderById(folderID);
var files = fldr.getFiles();
var s='';
var re = /^.*\.csv$/i;
while (files.hasNext())
{
var file = files.next();
var filename = file.getName();
if(filename.match(re))
{
s+=file.getBlob().getDataAsString().split('\n').splice(0,1).join('\n') + '\n';
//s += file.getBlob().getDataAsString() + '\n';
file.setName(filename.slice(0,-3) + 'old');
}
}
return s;
}
You may have to play with this a little. I'm not sure if the last '\n' is needed or not and I'm not that great at chaining so many operations. But you need to remove the headers from each file. You could write a local script that you give to your techs that strips off the headers at the origin and in that case then go back to the way it is now.