I am trying to edit this "Generate from Template" script. What the script does is based on a template it inputs information from a Spreadsheet to a Document. I like how it works except that it just names the document a copy of the template then the row number. This isn't very efficient for what i am trying to use this for. My question is how would i be able to do one of these options:
A: Have the name be based on a certain Cell in the row. For example, there is a column named Claim # and Department. I would like both of those to make up the title for each document. The document would be: " {department name} {claim #} " based on the information in that column in that row that was exported.
B: Have a box to put in when generating the document that asks what i want the file to be named.
Thank you for your help!
PS: If it is needed the columns that i would use for the name of the document are: column E then Column D.
This is the code: (I did not make this, i found it in the gallery.)
function generateDocument(e) {
var template = DocsList.getFileById(e.parameter.Templates);
var row = e.parameter.row
var myDocID = template.makeCopy(template.getName()+" - "+ row).getId();
var myDoc = DocumentApp.openById(myDocID);
var copyBody = myDoc.getActiveSection();
var Sheet = SpreadsheetApp.getActiveSpreadsheet();
//Browser.msgBox(row);
var myRow = SpreadsheetApp.getActiveSpreadsheet().getRange(row+":"+row);
for (var i=1;i<Sheet.getLastColumn()+1;i++){
var myCell = myRow.getCell(1, i);
copyBody.replaceText("{"+myCell.getA1Notation().replace(row,"")+"}", myCell.getValue());
}
myDoc.saveAndClose();
//var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
//MailApp.sendEmail(email_address, subject, body, {cc: carbonCopy, name: senderName, htmlBody: body, attachments: pdf});
var app = UiApp.getActiveApplication();
app.close();
return app;
}
function getTemplates() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle('Generate from template');
// Create a grid with 3 text boxes and corresponding labels
var grid = app.createGrid(3, 2);
grid.setWidget(0, 0, app.createLabel('Template name:'));
var list = app.createListBox();
list.setName('Templates');
grid.setWidget(0, 1, list);
var docs = DocsList.getFolder("Templates").getFilesByType("document");
for (var i = 0; i < docs.length; i++) {
list.addItem(docs[i].getName(),docs[i].getId());
}
grid.setWidget(1, 0, app.createLabel('Row:'));
var row = app.createTextBox().setName('row');
row.setValue(SpreadsheetApp.getActiveSpreadsheet().getActiveRange().getRow());
grid.setWidget(1, 1, row);
// Create a vertical panel..
var panel = app.createVerticalPanel();
// ...and add the grid to the panel
panel.add(grid);
// Create a button and click handler; pass in the grid object as a callback element and the handler as a click handler
// Identify the function b as the server click handler
var button = app.createButton('Submit');
var handler = app.createServerClickHandler('generateDocument');
handler.addCallbackElement(grid);
button.addClickHandler(handler);
// Add the button to the panel and the panel to the application, then display the application app in the Spreadsheet doc
panel.add(button);
app.add(panel);
doc.show(app);
}
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{name: "Generate from template", functionName: "getTemplates"}];
ss.addMenu("Template Generator", menuEntries);
}
The makeCopy method includes the possibility to give a name to the copy, the autocomplete shows it clearly
So in your code you could do it like this :
function generateDocument(e) {
var template = DocsList.getFileById(e.parameter.Templates);
var Sheet = SpreadsheetApp.getActiveSpreadsheet();// I moved this line a bit to have Sheet available
var row = e.parameter.row
var myDocID = template.makeCopy(Sheet.getRange('E'+row).getValue()+'-'+Sheet.getRange('D'+row).getValue()).getId();// this is a basic implementation to compose the name with content of column D and E separated by a hyphen... customize it the way you want.
...
Related
I am working on a Google Form that allows our employees to submit an in-field inspection of their equipment. I have a script that takes the form responses and creates a new sheet based on the date and the specific unit number of the equipment. The user goes through a checklist and selects either "Good" or "Needs Repair" for each item on the list. They can also add comments and upload pictures of any issues.
I am trying to have the script automatically send an email if "Needs Repair" is selected for any of the checks, as well as if the user adds a comment or a picture. This way we do not have to open every submitted sheet to know if any repairs are required. What I have is just not sending emails and I cannot figure out why. Any help is greatly appreciated!
Here is my current script:
function onFormSubmit() {
// onFormSubmit
// get submitted data and set variables
var ss = SpreadsheetApp.openById("*Spreadsheet Link*");
var sheet = ss.getSheetByName("Submissions");
var row = sheet.getLastRow();
var Col = sheet.getLastColumn();
var headings = sheet.getRange(1,1,1,Col).getValues();
var lastRow = sheet.getRange(row, 1, 1, Col);
var UnitNumber = sheet.getRange(row,3).getValue();
var newSheet = sheet.getRange(row,4,Col).getValue();
var fileExist = false;
var drillSheet = null;
var folder = DriveApp.getFoldersByName("Fraser Drill Inspections").next();
var files = folder.getFilesByName(UnitNumber);
var file = null;
var employee = sheet.getRange(row,2);
var checks = sheet.getRange(row, Col, 1, 20);
// check if Drill has sheet
while (files.hasNext())
{
fileExist = true;
file = files.next();
break;
}
if (fileExist) //If spreadsheet exists, insert new sheet
{
drillSheet = SpreadsheetApp.openById(file.getId());
drillSheet.insertSheet("" + newSheet);
}
else //create new spreadsheet if one doesn't exist
{
drillSheet = SpreadsheetApp.create(UnitNumber);
var ssID = drillSheet.getId();
file = DriveApp.getFileById(ssID);
file = file.makeCopy(UnitNumber, folder);
DriveApp.getFileById(ssID).setTrashed(true);
drillSheet = SpreadsheetApp.openById(file.getId());
drillSheet.renameActiveSheet(newSheet);
}
// copy submitted data to Drill sheet
drillSheet.getSheetByName(newSheet).getRange(1,1,1,Col).setValues(headings);
drillSheet.appendRow(lastRow.getValues()[0]);
drillSheet.appendRow(['=CONCATENATE(B6," ",B5)']);
drillSheet.appendRow(['=TRANSPOSE(B1:2)']);
//Hide top rows with raw data
var hiderange = drillSheet.getRange("A1:A3");
drillSheet.hideRow(hiderange);
//Widen columns
drillSheet.setColumnWidth(1,390);
drillSheet.setColumnWidth(2,700);
//Send email if there are any comments or if anything needs repair
if(lastRow.getValues() == "Needs Repair") {
function SendEmail() {
var ui = SpreadsheetApp.getUi();
MailApp.sendEmail("email#domain.com", "Drill Needs Repair", "This drill requires attention according to the most recent inspection report.")
}
}
}
The function to send an email is:
GmailApp.sendEmail(email, subject, body);
Try changing
if(lastRow.getValues() == "Needs Repair") {
function SendEmail() {
var ui = SpreadsheetApp.getUi();
MailApp.sendEmail("email#domain.com", "Drill Needs Repair", "This drill requires attention according to the most recent inspection report.")
}
}
to just the following:
if(lastRow.getValues() == "Needs Repair") {
GmailApp.sendEmail("youremail#domain.com", "Drill Needs Repair", "This drill requires attention according to the most recent inspection report.");
}
It looks like you've still got some additional work to do too, e.g. to make it send to the email address from the form submission instead of a hardcoded one.
I have a Google UI App that is designed to assist entering data into a google spreadsheet where most of the rows are identical. To do so an UI panel is created and text fields are used for each column of the spreadsheet. With the push of a button these values are appended to the spreadsheet.
I would like the button to then clear the contents of a single text box and maintain the values of the others to allow for entry of the next nearly identical item. My attempts to do so have resulted in "Error encountered: Object does not allow properties to be added or changed."
I have included a simplified version below, the actual script has many text boxes but this simplified example also shares the problem.
function showNewEntryDialog() {
var app = UiApp.createApplication();
app.setTitle("Add Multiple Items");
var panel = app.createVerticalPanel();
var grid = app.createGrid(9,3);
var nameTextBox = app.createTextBox();
var serialTextBox = app.createTextBox();
nameTextBox.setName('nameTextBox').setId('nameTextBox');
serialTextBox.setName('serialTextBox').setId('serialTextBox');
var snButton = app.createButton('Add and New SN')
grid.setWidget(0,0,app.createLabel('Name'));
grid.setWidget(0,1,nameTextBox);
grid.setWidget(4,0,app.createLabel('Serial Number'));
grid.setWidget(4,1,serialTextBox);
grid.setWidget(4,2,snButton);
panel.add(grid);
var snClickHandler = app.createServerClickHandler("respondToButtonPress");
snButton.addClickHandler(snClickHandler);
snClickHandler.addCallbackElement(panel);
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function respondToButtonPress(e) {
var app = UiApp.getActiveApplication();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow([e.parameter.nameTextBox,
e.parameter.serialTextBox]);
app.getElementById('serialTextBox').setText('');
// Does nothing?
app.getElementById('serialTextBox').setValue='';
// Error:Object does not allow changes
}
How can a button change the contents of a text box in the UI panel? If it cannot, in what other way can I achieve the behavior I desire?
Bryan's answer is correct but you could do it more efficiently using a clientHandler in your main function like this :
function showNewEntryDialog() {
var app = UiApp.createApplication();
app.setTitle("Add Multiple Items");
var panel = app.createVerticalPanel();
var grid = app.createGrid(9,3);
var nameTextBox = app.createTextBox();
var serialTextBox = app.createTextBox();
nameTextBox.setName('nameTextBox').setId('nameTextBox');
serialTextBox.setName('serialTextBox').setId('serialTextBox');
var snButton = app.createButton('Add and New SN')
grid.setWidget(0,0,app.createLabel('Name'));
grid.setWidget(0,1,nameTextBox);
grid.setWidget(4,0,app.createLabel('Serial Number'));
grid.setWidget(4,1,serialTextBox);
grid.setWidget(4,2,snButton);
panel.add(grid);
// a clientHandler : ----------------------------------------------------------
var cHandler = app.createClientHandler().forTargets(serialTextBox).setText('');
//-----------------------------------------------------------------------------
var snClickHandler = app.createServerClickHandler("respondToButtonPress");
snButton.addClickHandler(snClickHandler).addClickHandler(cHandler);// you can have multiple handlers on the same widget
snClickHandler.addCallbackElement(panel);
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function respondToButtonPress(e) {
var app = UiApp.getActiveApplication();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.appendRow([e.parameter.nameTextBox,
e.parameter.serialTextBox]);
}
Think .setText() and .setValue() essentially do the same thing so really only need one or the other. Your .setValue='' is invalid. Should be .setValue(''). Need a return app; at the end too.
I'm trying to create an app script to work inside a Google Site that has a search text box which is supposed to reference a Spreadsheet and spit out results from that search. The problem, I believe, exists in the second half of the code where I'm trying to reference the spreadsheet based on the text entered into the box provide by the code below.
function doGet(e) {
var doc = SpreadsheetApp.openById(SPREADSHEET_ID_GOES_HERE);
var app = UiApp.createApplication().setTitle('New app');
// Create the entry form, a 1 x 2 grid with text boxes for name, age, and city that is then added to a vertical panel
var grid = app.createGrid(1, 2);
grid.setWidget(0, 0, app.createLabel('Name:'));
grid.setWidget(0, 1, app.createTextBox().setName('userName').setId('userName'));
// Create a vertical panel and add the grid to the panel
var panel = app.createVerticalPanel();
panel.add(grid);
var buttonPanel = app.createHorizontalPanel();
var button = app.createButton('submit');
var submitHandler = app.createServerClickHandler('submit');
submitHandler.addCallbackElement(grid);
button.addClickHandler(submitHandler);
buttonPanel.add(button);
var closeButton = app.createButton('close');
var closeHandler = app.createServerClickHandler('close');
closeButton.addClickHandler(closeHandler);
buttonPanel.add(closeButton);
// Create label called statusLabel and make it invisible; add buttonPanel and statusLabel to the main display panel.
var statusLabel = app.createLabel().setId('status').setVisible(false);
panel.add(statusLabel);
panel.add(buttonPanel);
app.add(panel);
return app;
}
function close() {
var app = UiApp.getActiveApplication();
app.close();
return app;
}
The Problem exists in the code below. I'm trying to search the Spreadsheet using the text entered into the textBox. I'm not sure how to achieve this.
// function called when submit button is clicked
function submit(e) {
// Write the data in the text boxes back to the Spreadsheet
var cell = getValue(e.parameter.submit);
var doc = SpreadsheetApp.openById('SPREADSHEET_ID_GOES_HERE');
var ss = doc.getSheets()[0];
var lastRow = doc.getLastRow();
var data = ss.getRange(2, 1, 2, 4).getValues();
for(nn=0;nn<data.length;++nn){
if (data[nn][1]==cell){break} ;// if a match in column B is found, break the loop
}
// Make the status line visible and tell the user the possible actions
app.getElementById('status').setVisible(true).setText(data[nn][1]);
return app;
}
When the form is submitted, your handler function submit(e) receives an event, e. If we log the value of it with Logger.log(Utilities.jsonStringify(e)); we'll see that looks like this:
{"parameter":
{
"clientY":"52",
"clientX":"16",
"eventType":"click",
"ctrl":"false",
"meta":"false",
"source":"u146139935837",
"button":"1",
"alt":"false",
"userName":"Lucy",
"screenY":"137",
"screenX":"16",
"shift":"false",
"y":"14",
"x":"12"
}
}
We can access the value of our input boxes by name, for example e.parameter.userName.
One other tweak, we need to get a value for app. Here's what your working handler looks like:
// function called when submit button is clicked
function submit(e) {
var app = UiApp.getActiveApplication();
Logger.log(Utilities.jsonStringify(e)); // Log the input parameter (temporary)
// Write the data in the text boxes back to the Spreadsheet
var cell = e.parameter.userName;
var doc = SpreadsheetApp.openById('SPREADSHEET-ID');
var ss = doc.getSheets()[0];
var lastRow = doc.getLastRow();
var data = ss.getRange(2, 1, 2, 4).getValues();
var result = "User not found";
for (nn = 0; nn < data.length; ++nn) {
if (data[nn][1] == cell) {
result = data[nn][1];
break
}; // if a match in column B is found, break the loop
}
// Make the status line visible and tell the user the possible actions
app.getElementById('status').setVisible(true).setText(result);
return app;
}
I need request information before start to use my spreadsheet it is a date range, if you dont enter the date range the spreadsheet must be closed.
Thanks for your help.
You can implement an onOpen() function that would trigger the opening of a dialog and have the dialog remain open as long as the user does not enter the date range you want. I don't think you could force the closing of the spreadsheet if no value is entered though.
You can do that in a UI using UiApp, it would show a link to your spreadsheet only if a condition is validated,else it would reject the request.
EDIT : Here is an example to let you start with :
(the condition has to be defined, I commented the part that must be completed by you...
function doGet() {
var app = UiApp.createApplication().setStyleAttribute('padding', '15').setStyleAttribute('background', 'beige').setWidth('300').setHeight('140');// adjust dimensions to your needs
var mygrid = app.createGrid(3, 2);
mygrid.setWidget(0, 0, app.createLabel('StartDate:'));
mygrid.setWidget(0, 1, app.createDateBox().setId('dateA'));
mygrid.setWidget(1, 0, app.createLabel('EndDtate:'));
mygrid.setWidget(1, 1, app.createDateBox().setId('dateB'));
var mybutton = app.createButton('OK');
mybutton.setId("mybutton");
var mypanel = app.createVerticalPanel();
mypanel.setId('mypanel');
mypanel.add(mygrid);
var label = app.createHTML('<BR>Your request has been approved, <BR><BR>thanks for submitting').setId('Label').setStyleAttribute('padding', '15').setVisible(false).setWidth('300').setHeight('120');// adjust dimensions to your needs
var anchor = app.createAnchor('Open the Spreadsheet', 'https://docs.google.com/spreadsheet/ccc?key=0AnqSFd3iikE3dDljeXhtY3lacUtxdllQbGNHREY0VUE#gid=0').setId('anchor').setVisible(false)
mypanel.add(label).add(anchor)
mypanel.add(mybutton);
app.add(mypanel).add(label);
var handler = app.createServerHandler('checkDates');
handler.addCallbackElement(mypanel);
mybutton.addClickHandler(handler);
var Chandler = app.createClientHandler();
Chandler.forTargets(mygrid,mybutton).setVisible(false)
mybutton.addClickHandler(Chandler)
return app;
}
function checkDates(e) {
var app = UiApp.getActiveApplication();
var Label = app.getElementById('Label');
var anchor = app.getElementById('anchor');
Label.setVisible(true);// show the masking label with message
var dateA = e.parameter.dateA;
var dateB = e.parameter.dateB;
// write your condition...
// if(dateA)...&& dateB== ...
anchor.setVisible(true);
return app
// }else{
app.close
//return app}
}
I have been puzzled by this error. I have not been able to figure out what I am missing. Without the calls to headPanel the UI was working but would not insert the title or text label so I added the Horizontal panel in hopes of adding the text, but alas error. Please help me with this problem and I need to know what I am messing up.
function doGet(e){
var app = UiApp.createApplication();
var headPanel = app.createHorizontalPanel().setId('headPanel');
var header = app.setTitle('Detention Attendance');
var label = app.createLabel("Please enter attendance for Detention by clicking the checkbox next to the student's name if they were present. Then click Sumbit.");
headPanel.add(header); //* ERROR OCCURS HERE
headPanel.add(label);
app.add(pane);
var panel = app.createVerticalPanel();
var flexTable = app.createFlexTable().setStyleAttribute('border', '2px solid black')
.setStyleAttribute('borderCollapse','collapse')
.setBorderWidth(2);
//Get Data from spreadsheet
var spreadsheetId = 'xxxxxxxxxxxxxxxxxxxxxxxx';//Change it to your Spreadsheet ID
var dataArray = getData(spreadsheetId);
//Load data into table cells
Logger.log(dataArray);
for (var row = 0; row<dataArray.length; row++){
if (row > 0) {
var ticketDate = dataArray[row] [0];
var dateStamp = Utilities.formatDate(ticketDate, "America/Chicago", "MM/dd/yyyy");
Logger.log("dateStamp = " +dateStamp);
dataArray[row] [0] = dateStamp;
var ticketDate2 = dataArray[row] [16];
var dateStamp2 = Utilities.formatDate(ticketDate2, "America/Chicago", "MM/dd/yyyy");
dataArray[row] [16] = dateStamp2;
Logger.log("DateStamp = " +dateStamp2);
}
flexTable.setStyleAttribute("color", "purple").setText(row, 2, dataArray[row][2].toString()).setWidth('300px');
flexTable.setText(row, 0, dataArray[row][0].toString()).setWidth('600px');
flexTable.setText(row, 4, dataArray[row][16].toString()).setWidth('300px');
}
panel.add(flexTable);
app.add(panel);
return app;
}
function getData(spreadsheetId){
var ss = SpreadsheetApp.openById(spreadsheetId);
var sheet = ss.getSheets()[0].getDataRange();
Logger.log(sheet);
return sheet.getValues();
}
Your header var is a UiInstance - in fact it's the same instance as app, returned as a convenience for chaining by the call to .setTitle().
The .add() method is looking for a Widget as a parameter, and not finding it.
You don't need to keep that header var - it's only causing you trouble. In fact, you could set the Title as you create the UiApp instance:
var app = UiApp.createApplication().setTitle('Detention Attendance');