I have a problem.
How to get the filename from the url?
enter image description here
I wouldn't normally do this since you haven't shown us what you've tried, but I'm feeling generous.
This function should work for you. (Note that you'll need to grant permissions for it to run.)
function getFileNames() {
var sheet = SpreadsheetApp.getActive().getSheetByName("Get_File_Name");
var links = sheet.getRange("A2:A").getValues();
var filenames = [];
for (var i = 0; i < links.length; i++) {
var url = links[i][0];
if (url != "") {
var filename = SpreadsheetApp.openByUrl(links[i][0]).getName();
filenames.push([filename]);
}
}
var startRow = 2; // print in row 2 since row 1 is the header row
var fileNameColumn = 2; // Column B = column 2
var destination = sheet.getRange(startRow, fileNameColumn, filenames.length, filenames[0].length);
destination.setValues(filenames);
}
Another way
function getFileNames() {
var driveApp = DriveApp;
// SET THE SHEET HERE
var sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1");
//SET THE URL LINK COLUMN HERE : From row 2 since row 1 is the header row till last row
var links = sheet.getRange("P2:P").getValues();
var filenames = [];
for (var i = 0; i < links.length; i++) {
var fileId = getIdFromUrl(links[i][0]);
if (fileId != "" && fileId != null) {
var getfile = DriveApp.getFileById(fileId);
var filename = getfile.getName();
Logger.log(filename);
filenames.push([filename]);
} else {
filenames.push([""]);
}
}
// SET STARTING ROW TO PRINT: From row 2 since row 1 is the header row
var startRow = 2;
// SET WHICH COLUMN TO PRINT : Column A = column 1 / Column B = column 2
// MAKE SURE THE SHEET LAST COLUMN HEADER IS FILLED + 1 (next column)
var fileNameColumn = sheet.getLastColumn() + 1;
var destination = sheet.getRange(startRow, fileNameColumn, filenames.length, filenames[0].length);
destination.setValues(filenames);
}
function getIdFromUrl(url) { return url.match(/[-\w]{25,}/); }
You can create a custom function in spreadsheets like this.
function getSSName(name) {
var ss = SpreadsheetApp.openByUrl(url);
return ss.getName();
}
Related
I have this code with works brilliantly for me. I just need a small alteration to be able to select a range of cells as well, meaning:
Either H15-H17 or H22 or H26 in the attached image.enter image description here
the code I have is the following:
var CHECKBOX_CELLS = ["H15", "H22", "H26"];
function onEdit(e) {
var range = e.range;
var checkboxIndex = CHECKBOX_CELLS.indexOf(range.getA1Notation());
if (checkboxIndex > -1 && range.getValue() == true) {
var sheet = range.getSheet();
for (var i=0; i<CHECKBOX_CELLS.length; i++) {
if (i==checkboxIndex) continue;
sheet.getRange(CHECKBOX_CELLS[i]).setValue(false);
}
}
}
In here I am trying to make a checking where if the "STATUS" column is 'NEW FILE', then i would like to perform a file conversation from excel to spreadsheet.
For the "STATUS" column i created an IF-ELSE statement,
if (row[0] === "last week file") {
newValues.push(['OLD FILE'])
}
else{
newValues.push(['NEW FILE'])
ConvertFiles()
return
}
Therefore, I am making a check through the "STATUS", if the status column is empty it will be written as 'NEW FILE', and then it will perform an file conversion from excel to spreadsheet since i already called the method inside it.
Here is the EDITED version code of the file conversion:
function ConvertFiles() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range = sheet.getRange(2, 1, sheet.getLastRow()-1, 5); // get A2:E6 range
var data = range.getValues(); // get A2:E6 data
for(var i = 0; i < data.length; i++){
if(data[i][2] == " "){
for( var r= 2;r < sheet.getLastRow()+1; r++){
var fileId = sheet.getRange(r,1).getValue();
var folderID = sheet.getRange(r,2).getValue(); //for destination folder
var files = DriveApp.getFileById(fileId);
var name = files.getName().split('.')[0];
var blob = files.getBlob();
var newFile = {
title: name.replace('_converted','') + '_converted',
parents: [{id: folderID}] };
var destinationFolderId = DriveApp.getFolderById(folderID);
var existingFiles = destinationFolderId.getFilesByName(newFile.title);
while(existingFiles.hasNext()) {
var oldConvertedFileWithSameNameID = existingFiles.next().getId();
Drive.Files.remove(oldConvertedFileWithSameNameID,{supportsAllDrives: true});
}
var newFileID = Drive.Files.insert(newFile, blob, { convert: true,supportsAllDrives: true }).id;
Logger.log(newFileID);
var Url = "https://drive.google.com/open?id=" + newFileID;
//sheet.getRange(r,4).setValue(newFileID);
//sheet.getRange(r,5).setValue(Url);
}
sheet.getRange(i+2,4).setValue(newFileID); //set value in column D
sheet.getRange(i+2,5).setValue(Url); //set value in column E
}
}
}
The error that i am facing is, when i call the method ConvertFiles() inside the if statement, the conversion happens from row 2 until 6 CONTINOUSLY without stopping as shown in sample in red circle.
I only wanted to make conversion on the "NEW FILES" only which will be on row 5 and 6.
How can i make a conversion on the selected/specified row?
It would be more efficient if you obtain all the values in your Sheet, loop the 2D array the getValues() method will return and add an if statement that will only process new files.
Example:
Here in my example below I created a script that will only process rows that have a blank value for the status column.
Code:
function ConvertFiles() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range = sheet.getRange(2, 1, sheet.getLastRow()-1, 5); // get A2:E6 range
var data = range.getValues(); // get A2:E6 data
/*the content of data is 2D array,
each sub array represent rows in your table*/
for(var i = 0; i < data.length; i++){
if(data[i][2] == ""){ //the 2 in [i][2] represent the value of C column in sheet
//Add your file conversion code here
sheet.getRange(i+2,4).setValue("Test only"); //set value in column D
sheet.getRange(i+2,5).setValue("Test only"); //set value in column E
}
}
}
Data:
Output:
References:
Sheet.getRange(row, column, numRows, numColumns)
Range.getValues()
Range.setValue(value)
EDIT:
The value of data variable in the code below is a 2D array containing all the data in the range provided. In your example, it is the data of A2:E6.
Example output:
[
[fileId1,folderId1,Status1,,],
[fileId2,folderId2,Status2,,],
[fileId3,folderId3,Status3,,],
[fileId4,folderId4,,,],
[fileId5,folderId5,,,],
]
The for loop will access each sub array per iteration and since we already knew the position of our target data (fileID and folderID) we don't need to create another for loop to access it, instead we just specify the index on which the data is located. data[i][0] for file id and data[i][1] for folder id. The if(data[i][2] == "") is added to check if the column C of each row is empty and ignore the one with data.
Code:
function ConvertFiles() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var range = sheet.getRange(2, 1, sheet.getLastRow()-1, 5);
var data = range.getValues();
for(var i = 0; i < data.length; i++){
if(data[i][2] == ""){
var fileId = data[i][0];
var folderID = data[i][1];
var files = DriveApp.getFileById(fileId);
var name = files.getName().split('.')[0];
var blob = files.getBlob();
var newFile = {
title: name.replace('_converted','') + '_converted',
parents: [{id: folderID}] };
var destinationFolderId = DriveApp.getFolderById(folderID);
var existingFiles = destinationFolderId.getFilesByName(newFile.title);
while(existingFiles.hasNext()) {
var oldConvertedFileWithSameNameID = existingFiles.next().getId();
Drive.Files.remove(oldConvertedFileWithSameNameID,{supportsAllDrives: true});
}
var newFileID = Drive.Files.insert(newFile, blob, { convert: true,supportsAllDrives: true }).id;
var Url = "https://drive.google.com/open?id=" + newFileID;
sheet.getRange(i+2,4).setValue(newFileID);
sheet.getRange(i+2,5).setValue(Url);
}
}
}
Here is the GS code which will fetch the email id and and subject and the table.
var EMAIL_DRAFTED = "EMAIL DRAFTED";
function draftMyEmails() {
var sheet = SpreadsheetApp.getActiveSheet(); // Use data from the active sheet
var startRow = 2; // First row of data to process
var numRows = sheet.getLastRow() - 1; // Number of rows to process
var lastColumn = sheet.getLastColumn(); // Last column
var dataRange = sheet.getRange(startRow, 1, numRows, lastColumn) // Fetch the data range of the active sheet
var data = dataRange.getValues(); // Fetch values for each row in the range
// Work through each row in the spreadsheet
for (var i = 0; i < data.length; ++i) {
var row = data[i];
// Assign each row a variable
var clientName = row[0]; // Col A: Client name
var clientEmail = row[1]; // Col B: Client email
var sub = row[2]; // Col C: subject
var body = row[3]; // Col D: emailbody
var emailStatus = row[lastColumn - 1]; // Col E: Email Status
var range = sheet.getRange(2, 6, 1, 5).getDataRegion(SpreadsheetApp.Dimension.ROWS);
var values = range.getValues();
// Prevent from drafing duplicates and from drafting emails without a recipient
if (emailStatus !== EMAIL_DRAFTED && clientEmail) {
// Build the email message
var emailBody = '<p>Hi ' + clientName + ',<p>';
//emailBody += '<p>We are pleased to match you with your vegetable: <strong>' + veg + '</strong><p>';
//emailBody += '<h2>About ' + veg + '</h2>';
emailBody += '<p>' + values + '</p>';
// emailBody += '<p>' + clientName + ', we hope that you and ' + veg + ' have a wonderful relationship.<p>';
// Create the email draft
GmailApp.createDraft(
clientEmail, // Recipient
sub, // Subject
'', // Body (plain text)
{
htmlBody: emailBody // Options: Body (HTML)
}
);
sheet.getRange(startRow + i, lastColumn).setValue(EMAIL_DRAFTED); // Update the last column with "EMAIL_DRAFTED"
SpreadsheetApp.flush(); // Make sure the last cell is updated right away
}
}
}
What i am getting is by using this code:
Body
7 & 8,9 & 10,IOS,5 & 6,,a,b,c,d,,1,2,3,4,,1,2,3,4,,1,2,3,4,,1,2,3,4,,1,2,3,4,,1,2,3,4,,1,2,3,4,,1,2,3,4,
expected result should be like this.
This how the google sheet looks like.
Try this:
function draftMyEmails() {
var sh=SpreadsheetApp.getActiveSheet();
var startRow=2;
var lastCol=sh.getLastColumn();
var dataRange=sh.getRange(startRow,1,sh.getLastRow()-startRow+1,lastCol);
var data=dataRange.getValues();
for (var i=0;i<data.length;i++) {
var row=data[i];
var clientName=row[0];
var clientEmail=row[1];
var sub=row[2];
var body=row[3];
var emailStatus=row[lastCol-1];
var range=sh.getRange(2, 6, 1, 5).getDataRegion(SpreadsheetApp.Dimension.ROWS);
var values=range.getValues();
if (emailStatus!="EMAIL DRAFTED" && clientEmail) {
var emailBody= Utilities.formatString('<p>Hi %s </p>,<br />',clientName);
emailBody+='<style>td{border:1px solid black;)</style><table>';
values.forEach(function(r,j){
emailbody+='<tr>
r.foreach(function(c,k){
emailBody+=Utilities.formatString('<td>%s</td>',c);
});
emailBody+='</tr>';
});
emailBody+='</table>';
GmailApp.createDraft(clientEmail,sub,'',{htmlBody: emailBody});
sh.getRange(startRow + i, lastColumn).setValue("EMAIL_DRAFTED");
}
}
}
Please provide me with an image of your spreadsheet so I can see what your table looks like and I'll debug the table area for you or you can do it yourself.
I just started using Google Sheets and I'm having trouble when setting a script.
I need a cell (let's say "AF4") to get the last modification date of another cell (let's say "X4").
Here's my script so far:
`function onEdit(e)
{
var sheet = SpreadsheetApp.getActiveSheet();
var editRange = sheet.getActiveRange();
var editRow = editRange.getRow();
var editCol = editRange.getColumn();
var range = sheet.getRange("X4");
var rangeRow = range.getRow();
var rangeCol = range.getColumn();
if (editRow = rangeRow && editCol = rangeCol)
{
sheet.getRange("AF4").setValue(new Date());
}
}`
When I try to save it, it says "invalid transfer on left side, line 1, "code" "
I'd really apprecite any help with that.
Thank you,
CURTY
The syntax for your condition seems to be wrong, that's why the error appears :)
if (editRow = rangeRow && editCol = rangeCol)
in case you want to check based on more conditions, the syntax must be
if (condition) {
block of code to be executed if the condition is true
if (condition) {
block of code to be executed if the condition is true
}
}`
I modified a bit of your code that you get an idea, of what needs to be done in order to achieve your goal, this script to get the last modification date of column X and post "new date" into AF4 (so whenever you edit something on column "x" and the row 4 the date will be set in AF4)
function onEdit() {
var sheet = SpreadsheetApp.getActiveSheet();
var editRange = sheet.getActiveRange();
var editRow = editRange.getRow();
var editCol = editRange.getColumn();
var editCell = sheet.getActiveCell();
var range = sheet.getRange("X4");
var rangeRow = range.getRow();
var rangeCol = range.getColumn();
if( sheet.getName() == "Sheet1" ) { //checks that we're on the correct sheet
if( editCell.getColumn() == 24 ) { //checks that we're on the correct column ; column x = 24
if( editCell.getRow() == 4 ) { //checks that we're on the correct row ; row 4 = 4
sheet.getRange("AF4").setValue(new Date());
SpreadsheetApp.getActive().toast('Data changed', 'Info', 2); //give a Info, that something was done correctly
}
}
}
}
Hope this will help you!
EDIT
Script from comments request, whenever something on Column X is changed, add Date to column AF in the same row
function onEdit() {
var sheet = SpreadsheetApp.getActiveSheet();
var editRange = sheet.getActiveRange();
var editCol = editRange.getColumn();
var editCell = sheet.getActiveCell();
var range = sheet.getRange("X4");
if( editCell.getColumn() == 24 ) {
var rangeCol = range.getColumn();
var editRow = editRange.getRow();
sheet.getRange(editRow,rangeCol+8).setValue(new Date()); //use the RangeCol + 8 Columns
SpreadsheetApp.getActive().toast('Date added', 'Info', 2); //this line can be deleted
}
}
So I have some code to create calendar events based on a jobs sheet for meetings but I can't seem to get it working as I would expect- I have columns 24 and 25 to keep track of if its been put in the calendar and the calendar event id, I don't want it to delete then create a new event for ones that have already been added (as this spreadsheet can get large) so thats why I keep track via on edit. But is seems to create a new event every time. If anyone can have a look over that would be great as I've been struggling for the past 3 days with this.
Many thanks
//push new events to calendar;
function pushToCalendar() {
//spreadsheet variables
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
var range = sheet.getRange(2,1,lastRow,26);
var values = range.getValues();
var updateRange = sheet.getRange('Z1');
//calendar variables
var calendar = CalendarApp.getCalendarById('insert calendar code here')
//show updating message
updateRange.setFontColor('red');
var numValues = 0;
for (var i = 0; i < values.length; i++) {
//check to see if name are filled out
if ((values[i][0].length > 0) && (values[i][1].length > 0)) {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if it has been edited delete old event
if (values[i][23] ='n') {
try{
var eventIdCell =values[i][24];
var eventId =calendar.getEventSeriesById(eventIdCell);
eventId.deleteEventSeries();
}
catch (e) {
// do nothing - we just want to delete if it has been edited and the old event if it still exists
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//check if it's been entered before
if (values[i][23] !='y') {
var newEventTitle = values[i][0] + ' - ' + values[i][1]+' - ' + 'Sample';
var newEvent = calendar.createAllDayEvent(newEventTitle, new Date(values[i][6]));
//get ID
var newEventId = newEvent.getId();
//mark as entered, enter ID
sheet.getRange(i+2,24).setValue('y');
sheet.getRange(i+2,25).setValue(newEventId);
}
}
numValues++;
}
//hide updating message
updateRange.setFontColor('white');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//add a menu when the spreadsheet is opened
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [];
menuEntries.push({name: "Update Calendar", functionName: "pushToCalendar"});
sheet.addMenu("Jobs Calendar", menuEntries);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
function onEdit(event){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var actSht = event.source.getActiveSheet();
var actRng = event.source.getActiveRange();
var activeCell = actSht.getActiveCell();
var row = activeCell.getRow();
if(row < 2){
return; //If header row then return
}
else{
var index = actRng.getRowIndex();
var updateCalCell = actSht.getRange(index,24);
var eventIdCell = actSht.getRange(index,25);
change updated on colander status to n
updateCalCell.setValue('n');
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
You made a simple error in the condition : the EQUAL operator in comparison is == and not =, change that and it will work.
if (values[i][23] =='n') {