Google Apps Script to Email Active Spreadsheet - email

I found a script online that takes the current sheet, copies it to a temporary new spreadsheet, converts it to PDF and emails it. I was able to get it working but trying to set it up so that it only sends a certain range. Tried to play with it a bit but I am not a good coder by any stretch. Alternatively I'd be interested also in figuring out how to get it to fit to 1 page PDF in landscape, convert without gridlines (my online research shows this ins't possible?) or even send as XLS.
// Simple function to send Weekly Status Sheets to contacts listed on the "Contacts" sheet in the MPD.
// Load a menu item called "Project Admin" with a submenu item called "Send Status"
// Running this, sends the currently open sheet, as a PDF attachment
function onOpen() {
var submenu = [{name:"Send Status", functionName:"exportSomeSheets"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Project Admin', submenu);
}
function exportSomeSheets() {
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive();
// Set the message to attach to the email.
var message = "Please see attached"; // Could make it a pop-up perhaps, but out of wine today
// Get Project Name from Cell A1
var projectname = originalSpreadsheet.getRange("A1:A1").getValues();
// Get Reporting Period from Cell B3
var period = originalSpreadsheet.getRange("B3:B3").getValues();
// Construct the Subject Line
var subject = projectname + " - Weekly Status Sheet - " + period;
// Get contact details from "Contacts" sheet and construct To: Header
// Would be nice to include "Name" as well, to make contacts look prettier, one day.
var contacts = originalSpreadsheet.getSheetByName("Contacts");
var numRows = contacts.getLastRow();
var emailTo = contacts.getRange(2, 2, numRows, 1).getValues();
// Google scripts can't export just one Sheet from a Spreadsheet
// So we have this disgusting hack
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
// Find and delete the default "Sheet 1", after the copy to avoid triggering an apocalypse
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
// Make zee PDF, currently called "Weekly status.pdf"
// When I'm smart, filename will include a date and project name
var pdf = DocsList.getFileById(newSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Weekly Status.pdf',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
// Delete the wasted sheet we created, so our Drive stays tidy.
DocsList.getFileById(newSpreadsheet.getId()).setTrashed(true);
}

To send a single sheet you may hide all other before sending.
var sheet_to_send = 'Sheet1';
//-----------------------------
var as = SpreadsheetApp.getActiveSpreadsheet();
var sheets = as.getSheets();
for(var i in sheets){
if (sheets[i].getName()!=sheet_to_send){
sheets[i].hideSheet();
}
}
MailApp.sendEmail(email_to, email_subject, email_body, {attachments: SpreadsheetApp.getActiveSpreadsheet()});
for(var i in sheets){
if (sheets[i].getName()!=sheet_to_send){
sheets[i].showSheet();
}
}
If you have more sheets to send, you would filter them with a javascript object:
var sheets_to_send = {'Sheet1':1, 'Sheet3': 1};
...
// replace
if (sheets[i].getName()!=sheet_to_send)
// by
if (!(sheets[i].getName() in sheet_to_send))

I am using this code to automatically send a google spreadsheet with email in pdf format. it works fine, but I need to customize the pdf by removing the grid lines and set display A4 . Is there a way ? thanks
Simple function to send Weekly Status Sheets to contacts listed on the "Contacts" sheet in the MPD.
// Load a menu item called "Project Admin" with a submenu item called "Send Status"
// Running this, sends the currently open sheet, as a PDF attachment
function onOpen() {
var submenu = [{name:"Invia", functionName:"exportSomeSheets"}];
SpreadsheetApp.getActiveSpreadsheet().addMenu('Invia PDF', submenu);
}
function exportSomeSheets() {
// Set the Active Spreadsheet so we don't forget
var originalSpreadsheet = SpreadsheetApp.getActive();
// Set the message to attach to the email.
var message = "Messaggio email";
// Get Project Name from Cell A1
var projectname = originalSpreadsheet.getRange("A1:A1").getValues();
// Get Reporting Period from Cell A2
var period = originalSpreadsheet.getRange("A2:A2").getValues();
// Construct the Subject Line
var subject = projectname;
// Get contact details from "Contacts" sheet and construct To: Header
// Would be nice to include "Name" as well, to make contacts look prettier, one day.
var emailTo = originalSpreadsheet.getRange("A3:A3").getValues();
// Create a new Spreadsheet and copy the current sheet into it.
var newSpreadsheet = SpreadsheetApp.create("Spreadsheet to export");
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var projectname = SpreadsheetApp.getActiveSpreadsheet();
sheet = originalSpreadsheet.getActiveSheet();
sheet.copyTo(newSpreadsheet);
var aliases = GmailApp.getAliases()
Logger.log(aliases);
Logger.log(aliases[2]); //returns the alias located at position 0 of the aliases array
// Make zee PDF, currently called "Weekly status.pdf"
// When I'm smart, filename will include a date and project name
var pdf = DocsList.getFileById(originalSpreadsheet.getId()).getAs('application/pdf').getBytes();
var attach = {fileName:'Nome_allegato',content:pdf, mimeType:'application/pdf'};
// Send the freshly constructed email
GmailApp.sendEmail(emailTo, subject, message, {'from': aliases[2], attachments:[attach]});
// Delete the wasted sheet we created, so our Drive stays tidy.
DocsList.getFileById(newSpreadsheet.getId()).setTrashed(true);
}

In order to split a spreadsheet up, you must first copy the parts into a temporary sheet and then copy that sheet into a new spreadsheet.
Here is my code to replace yours from 'Create spreadsheet...' to where you delete Sheet1 of the new spreadsheet.
//variables firstRow & lastRow define the part of the sheet to copy
//create new spreadsheet
var newSpreadsheet = SpreadsheetApp.create('Spreadsheet to export');
//create temporary sheet to copy to new spreadsheet
var tempSheet = originalSpreadsheet.insertSheet();
//if header copy it
if (sheet.getFrozenRows() > 0)
{
dataSheet.getRange( 1, 1, sheet.getFrozenRows() ).copyTo( tempSheet.getRange(1,1) );
}
//copy relevant data to temporary sheet
dataSheet.getRange( firstRow, 1, lastRow - firstRow + 1 ).copyTo(tempSheet.getRange( sheet.getFrozenRows() + 1, 1 ));
//copy temp sheet to new spreadsheet
tempSheet.copyTo( newSpreadsheet );
//delete Sheet1 in new spreadsheet
newSpreadsheet.getSheetByName('Sheet1').activate();
newSpreadsheet.deleteActiveSheet();
//delete temp sheet
originalSpreadsheet.setActiveSheet(tempSheet);
originalSpreadsheet.deleteActiveSheet();

Related

How to add and edit a short answer in multiple google forms

So I have multiple google forms (around 20 forms), that I need to do 2 things to them:
1- These 20 forms are placed in a folder in my google drive. I need to add more like an "Access code" where users will have to insert in order to continue the solving the quiz.
The way I did that was to add a "short answer" question to "section 1" of the quiz asking "Enter your Access Code", add "response validation", "Regular expression" and "Pattern". Also making this a "required question". This should look something like the below picture
Example of google form
So is it possible to have a scriptto add this question to all 20 forms
2- The "access code" in these google forms will have to be updated frequently, so I don' want to be updating the "Pattern" manually for each form, is t possible to have a google script to edit the value of the pattern for each form
Thanks in advance guys :)
I managed to solve this issue that I was having, through looking for different codes and here are the codes that I used.
N.B. The codes might not be very clean as I was copying them from other parts/projects, but they have worked for me
1- Update the 20 forms with adding the access code question, I figured it was not possible to add a question at a certain position in the google form, however I can add a question at the end of the form and then move this item to the position I want:
function AddAccesscodeQ() {
var filess = DriveApp.getFolderById("Drive id>").getFiles();
while (filess.hasNext()) {
var file = filess.next();
var form = FormApp.openById(file.getId());
var sectionIndex= 0; // Please set the index you want to insert.
//I added a "sample item" to be moved and edited later
var newItemQ = form.addTextItem().setTitle("New sample item").getIndex(); // New sample item
// I added a Pagebreak that also should be moved after the questions "Enter Your Access Code"
var newItemPB = form.addPageBreakItem().getIndex();
var items = form.getItems(FormApp.ItemType.PAGE_BREAK);
var sections = [0];
for (var i = 0; i < items.length; i++) {
// I pushed the items in the google form twice downwards, to be able to move the "sample item" and "Page break" to the top of the form
sections.push(items[i].getIndex());
sections.push(items[i].getIndex());
}
var insertIndex = sections[sectionIndex + 1] || null;
if (insertIndex) {
// Here I moved the 2 new items to the desired positions
form.moveItem(newItemQ, 0);
form.moveItem(newItemPB, 1);
}
// Here I am going to edit the "Sample Question" to be as desired
var itemss = form.getItems();
var itemID = itemss[0].getId();
var itemse = form.getItemById(itemID).asTextItem()
.setTitle('Enter Your Access Code').setRequired(true);
//Create validation rule
var validation = FormApp.createTextValidation()
.setHelpText('Invalid Code')
.requireTextMatchesPattern("<Access Code>")
.build();
itemse.setValidation(validation);
}
}
2- The second problem was that I later might need to change this access code to a new one for the 20 forms
function UpdateAccessCode() {
var filesPhCH = DriveApp.getFolderById("<Drive ID>").getFiles();
while (filesPhCH.hasNext()) {
var file = filesPhCH.next();
var form = FormApp.openById(file.getId());
var items = form.getItems();
//Loop through the items and list them
for (var i = 0;i<items.length;i++){
var item = items[i];
var itemID = item.getId();
var itemtitle = item.getTitle();
var itemindex = item.getIndex();
// I found no need to continue the for loop since the items that need modification are at the top of the form
if (itemindex == 0){
break;
}
}
//Select the question you want to update
var itemse = form.getItemById(itemID).asTextItem()
.setTitle('Enter Your Access Code');
//Create validation rule
var validation = FormApp.createTextValidation()
//.setTitle('Enter Your Access Code');
.setHelpText('Invalid Code')
.requireTextMatchesPattern("<Enter the new Access Code>")
.build();
itemse.setValidation(validation);
}
}
I hope this might help someone as it has saved a lot of time for me ;)

Google Sheets - Code to send an email to an address in a cell upon selection of a dropdown menu cell

I know very little about code and am simply looking for help if someone knows how to do this. I have a google spreadsheet and for this example let's say
Column A is an email address
Column B is text
Column C is a dropdown list of items made using the Data Validation tool (pending, scheduled and complete).
I need a code that upon selecting "Complete" in column C, an email is sent to the recipient in column A with the body of the email containing the text from column B.
Any help is appreciated as I'm not a developer, I'm a pastor trying to help my church run more smooth.
and here's the link to the spreadsheet... https://docs.google.com/spreadsheets/d/1bA-gDvZ_jbJMyU6IqExBjHKclrKmqJSMHyuKHsr2CMA/edit?usp=sharing
and here's the script...
var sheetname = "FacilitiesWorkRequests";
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var range = sheet.getRange(1, 3, sheet.getLastRow(), 1);
var list = SpreadsheetApp.newDataValidation().requireValueInList(["pending", "scheduled", "complete"], true).build();
range.setDataValidation(list);
}
function onEdit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var ac = sheet.getActiveCell();
if (ac.getValue() == "complete") {
data = sheet.getRange(ac.getRowIndex(), 1, 1, 2).getValues();
Logger.log(data)
MailApp.sendEmail({
to: data[0][0],
subject: "sample mail",
body: data[0][1]
});
}
}
How about this sample?
var sheetname = "Here, please input your sheet name.";
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var range = sheet.getRange(1, 3, sheet.getLastRow(), 1);
var list = SpreadsheetApp.newDataValidation().requireValueInList(["pending", "scheduled", "complete"], true).build();
range.setDataValidation(list);
}
function onEdit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var ac = sheet.getActiveCell();
if (ac.getValue() == "complete") {
data = sheet.getRange(ac.getRowIndex(), 1, 1, 2).getValues();
Logger.log(data)
MailApp.sendEmail({
to: data[0][0],
subject: "sample mail",
body: data[0][1]
});
}
}
Please copy and paste this script to the script editor on spreadsheet, and set a sheet name you use, and then install a trigger. How to install a trigger is as follows. You can see the detailed information of this at https://developers.google.com/apps-script/guides/triggers/installable#google_apps_triggers.
At the script editor, choose "Resources" - "Current project's triggers".
Click "here" and add a trigger.
Under Run, select the function of "onEdit()".
Event is "From spreadsheet" - "Change of value".
For this sample script, when you open spreadsheet with this script, the dropdown list is applied, while the existing dropdown list is not changed. Because if you had added new row, new dropdown list is added. When you run this script, if authentication screen appears, please authenticate it.
And when you choose "complete" from the dropdown list, an e-mail is sent using e-mail of same row you chose. E-mail body is column B of same row.
If this will be helpful, I'm glad.

Script for removing rows in Google sheets

I'm in need of a script that removes, not just deleting, rows in Google sheets.
Having a form that supplies responses to a sheet, and for now I have to manually log in and remove the responses.
So a simple script that triggers every saturday, removing form responses from a sheet is what I need.
Code to delete rows:
function deleteResponses() {
var ss = SpreadsheetApp.openById("File ID");
var sheet = ss.getSheets()[3];
sheet.deleteRows(2, 200);
};
To add code: Under the TOOLS menu, choose SCRIPT EDITOR. Add this code.
Alternate code to clear the sheet:
function deleteResponses() {
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheets()[0];
sheet.clear();
};
Get your spreadsheet ID, and replace it in the "id" parameter. Then under the RESOURCES menu, choose CURRENT PROJECTS TRIGGERS.

Google Apps upload from spreadsheet: cannot reference active cell

I have this google app script which should
show file upload dialog
store file in google drive
write the url of the file into the current cell
All goes well except step 3, where the cell updated is always cell A1 in the first sheet. But the cursor is on sheet #3 on another cell.
function onOpen(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var menuEntries = [];
menuEntries.push({name: "File...", functionName: "doGet"});
ss.addMenu("Attach ...", menuEntries);
}
function doGet(e) {
var app = UiApp.createApplication().setTitle("Attach file to sheet");
var form = app.createFormPanel().setId('frm').setEncoding('multipart/form-data');
var formContent = app.createVerticalPanel();
form.add(formContent);
formContent.add(app.createFileUpload().setName('thefile'));
formContent.add(app.createSubmitButton('Submit'));
app.add(form);
SpreadsheetApp.getActiveSpreadsheet().show(app);
return app;
}
function doPost(e) {
var fileBlob = e.parameter.thefile;
var doc = DocsList.getFolderById('0B0uw1JCogWHuc29FWFJMWmc3Z1k').createFile(fileBlob);
var app = UiApp.getActiveApplication();
var label = app.createLabel('file uploaded successfully');
var value = '=hyperlink("' + doc.getUrl() + '","' + doc.getName() + '")'
app.add(label);
app.close();
SpreadsheetApp.getActiveSheet().getActiveCell().setValue(value);
return app;
}
I tried SpreadsheetApp.getActiveSheet().getActiveCell().setValue(value); outside of the doPost() function and this works when called in a normal context. What am I missing here?
judging from this answer, it is not possible to get the current spreadsheet/cell from the doPost function, the way I got it working is to get it in the doGet function via hidden fields and pass it via the form. Full blown working example here.

How to have an Apps Script Gadget display results directly in the UI

On my Google Site I've inserted an Apps Script Gadget (by pasting the URL of an Apps Script that I published as a service). This Apps Script allows the user to enter a value (their 'Blow Number') and view the corresponding data (based on API calls to my Google Fusion tables).
Right now, the script returns 3 hyperlinks:
Click here for a table of Blow Number 1
Click here for a chart of Blow Number 1
Click here for a map of Blow Number 1
This is because my script function getblowdetails has 3 app.createAnchor variables. Instead of having the script return 3 hyperlinks (that the user has to click on and view the resulting URL in a new window), I would like for the script to automatically invoke the 3 URLs and display the table, chart, and map in panels on the same page.
So the user would enter their Blow Number and press enter. They would then view the table, chart, and map directly below the text box on the same web page.
Please see the Code that I've included below and advise...Thanks for the help- I'm an apps-script novice so a thorough and understand-able response is greatly appreciated!
Code
Note: I've removed the URLs from the createAnchor variables because I'm only allowed to include 2 links in the post, but you can see them by going to www.OnSiteBAC.com/ViewMyBlows and entering Blow Number = 1...then click on the hyperlinks.
function doGet() {
var app = UiApp.createApplication();
// Create input boxes, buttons, labels, and links
var textBoxA = app.createTextBox().setId('textBoxA').setName('textBoxA').setFocus(true);
var buttonA = app.createButton('Get Blow Details').setEnabled(false);
var label = app.createLabel('Please enter your Blow Number here');
var link = app.createAnchor('where can I find my Blow Number?', 'http://www.onsitebac.com');
// Create a handler to call the getblowdetails function.
// A validation is added to this handler so that it will only invoke 'getblowdetails' if textBoxA contains a number
var handler = app.createServerClickHandler('getblowdetails').validateNumber(textBoxA).addCallbackElement(textBoxA);
// Create a handler to enable the button if all input is legal
var onValidInput = app.createClientHandler().validateNumber(textBoxA).forTargets(buttonA).setEnabled(true).forTargets(label, link).setVisible(false);
// Create a handler to mark invalid input in textBoxA and disable the button
var onInvalidInput1 = app.createClientHandler().validateNotNumber(textBoxA).forTargets(buttonA).setEnabled(false).forTargets(textBoxA).setStyleAttribute("color", "red").forTargets(label, link).setVisible(true);
// Create a handler to mark the input in textBoxA as valid
var onValidInput1 = app.createClientHandler().validateNumber(textBoxA).forTargets(textBoxA).setStyleAttribute("color", "black");
// only fire ServerHandler for onKeyUp if it passes validation
var textBoxHandler = app.createServerHandler('textBoxHandlerFunction');
// Add all the handlers to be called when the user types in the text boxes
textBoxHandler.addCallbackElement(textBoxA);
textBoxA.addKeyUpHandler(onInvalidInput1);
textBoxA.addKeyUpHandler(onValidInput1);
textBoxA.addKeyUpHandler(onValidInput);
textBoxA.addKeyUpHandler(textBoxHandler);
buttonA.addClickHandler(handler);
app.add(textBoxA);
app.add(buttonA);
app.add(label);
app.add(link);
return app;
}
function textBoxHandlerFunction(e) {
var app = UiApp.getActiveApplication();
if (e.parameter.keyCode == 13)
{
app = getblowdetails(e);
}
return app;
}
function getblowdetails(e) {
var app = UiApp.getActiveApplication();
var panel2 = app.createVerticalPanel();
var link2 = app.createAnchor ().setStyleAttribute("color", "green");
var panel3 = app.createVerticalPanel();
var link3 = app.createAnchor ();
var panel4 = app.createVerticalPanel();
var link4 = app.createAnchor ();
panel3.add(link3);
app.add(panel3);
panel4.add(link4);
app.add(panel4);
return app;
}
I don't think you'll be able to actually download the result and show it. So, there's no easy solution.
But you can build that table and chart on Apps Script easily (assuming you can already fetch the info from tables using its API).
The last issue is the map. On Apps Script you can only create static maps, meaning, an image. You can add custom markers and polygons, set the zoom, etc. But in the end it's a photo. The user will not be able to drag it around or use the map as an embedded google map as one would expect.