I am building a simple Google App Script that sends an e-mail every month with a file attached.
The file is updated with :
-the first day of the current month
-the last day of the current month
-the name of the month
All document creation and fields modification works well (I see the gdoc with modified fields few seconds after the script is launched).
The problem is that I receive an e-mail WITHOUT the modified fields in the attachment.
Does anyone knows WHY THE CHILD DOCUMENT IS MODIFIED WELL, BUT THE PDF VERSION ATTACHED TO THE EMAIL HASN'T ITS FIELDS MODIFIED ?
Thank you !
function myFunction() {
//DEALS WITH DATES
//Create a date
var today = new Date();
//Create a variable that will take month's values
var Mois = ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Decembre"];
//Get the current month
var MoisNum = today.getMonth()+1;
var TextMois = Mois[MoisNum-1];
//Get the number of first day of the month, and last day of the month
var Jour = today.getDate();
var NombreJourMois = ["31", "28", "31","30","31","30","31","31","30","31","30","31"];
var DernierJourMois = NombreJourMois[MoisNum-1];
//Get the current year
var Annee = today.getYear();
//Sets two variable with the date of the first day of the month and last day of the month
var DateDebutMois = 01+'/'+MoisNum+'/'+Annee;
var DateFinMois = DernierJourMois+'/'+MoisNum+'/'+Annee;
//CREATE A COPY OF THE PARENT FILE AND PUT IT IN THE RIGHT FOLDER
//Dossier de destination et fichier template
var DossierSource = DriveApp.getFolderById('0B0mCpRQd5BQidmQ2MGl4em9MRzA');
var DossierCible = DriveApp.getFolderById("13pril4REhDrITljX523z7LdQgVpOcazU");
var FichierSource = DriveApp.getFileById('109_Kuoxjh-C56MYeFhyyP-PhYJirCD5OVhuce0v7osI');
//Create a copy of the document and put it in the above folder
var Enfant = FichierSource.makeCopy();
DossierCible.addFile(Enfant);
DossierSource.removeFile(Enfant);
//MODIFY CHILD DOCUMENT WITH THE PROPER DATES AND RENAME IT
//Get the body of the child document
var BodyEnfant = DocumentApp.openById(Enfant.getId()).getBody();
//Replace date fields of the body by the right dates, and changes the name of the child document
BodyEnfant.replaceText('{1erDuMois}', DateDebutMois);
BodyEnfant.replaceText('{DernierDuMois}',DateFinMois);
Enfant.setName('Quittance de loyer - 218 rue de Grenelle - '+DateDebutMois);
//SEND AND EMAIL WITH THE DOCUMENT ATTACHED
var recipient = 'jean-marie.laly#magicmakers.fr';
var subject = 'Quittance de loyer - '+TextMois+' - '+Annee;
var body = 'Bonjour, Veuillez trouver ci-joint la quittance de loyer du mois de '+TextMois;
var pdf = Enfant.getAs("application/pdf");
GmailApp.sendEmail(recipient, subject, body, {attachments: [pdf],name: ''});
}
I think that the reason of your issue is because the modified values are not saved. So please convert to the PDF after the document was saved. In order to save the modified values to the document, how about this modification for your script?
Here, only modification part in your script was shown.
From :
//Get the body of the child document
var BodyEnfant = DocumentApp.openById(Enfant.getId()).getBody();
//Replace date fields of the body by the right dates, and changes the name of the child document
BodyEnfant.replaceText('{1erDuMois}', DateDebutMois);
BodyEnfant.replaceText('{DernierDuMois}',DateFinMois);
Enfant.setName('Quittance de loyer - 218 rue de Grenelle - '+DateDebutMois);
To :
//Get the body of the child document
var doc = DocumentApp.openById(Enfant.getId()); // Modified
var BodyEnfant = doc.getBody(); // Modified
//Replace date fields of the body by the right dates, and changes the name of the child document
BodyEnfant.replaceText('{1erDuMois}', DateDebutMois);
BodyEnfant.replaceText('{DernierDuMois}',DateFinMois);
Enfant.setName('Quittance de loyer - 218 rue de Grenelle - '+DateDebutMois);
doc.saveAndClose(); // Added
Reference :
saveAndClose()
If this was not what you want, please tell me. I would like to modify it.
Related
I had followed this question to create a table -> Excel table in HTML throught Javascript
My table is connected to a calendar created throught fullCalendar library and I implamented this table in a modal.
I also found a way to get the current visualized month as header of the table (by using getView). But now I have this bug:
This is how my table show up the first time I open it (it's the correct viewing): normal
and this is how it shows up when I open it the second time, also in a different month: wrong one
These are the mod I did to the code linked to the question added at the begining here:
function renderTable($targetTable, date, view, element ) {
var view = $('#calendar').fullCalendar('getView');
var start = view.intervalStart._d;
var end = view.intervalEnd.subtract(1, 'days');
alert(end);
//prende mese e anno attualmente visualizzati e lo imposta come titolo del modal nell'HTML
const months = ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"];
//calcola il numero dei giorni nel mese (30/31/28)
let numberOfDaysInMonth = new Date(end).getDate(); // just get the last day
//create the table header to display the month and date, and make is span all the days + the names column + the total column.
let $tableHeader = $(`<tr><th colspan="${numberOfDaysInMonth+2}" style="text-align: center;">${months[start.getMonth()]} ${start.getFullYear()}</th></tr>`)
I found the solution
Basically where i call the function that build my table I added this:
//table2 is the ID of my table
var table = document.getElementById('table2');
//i check if the table is empty; if it is than I render the thead and tbody
if (table.rows.length == 0){
var date = new Date();
renderTable($('#table2'), date);
}
//if not, before I delete whats inside and than I render it
else if(table.rows.lenght != 0){
$("#table2 thead").empty();
$("#table2 tbody").empty();
var date = new Date();
renderTable($('#table2'), date);
}
I am a teacher designing a tool to take attendance from Zoom usage data (the days we live in!)
Zoom provides reports that you can copy and paste and stay formatted as a table. Like this:
Luke Name Name
lr#email.com
09/10/2020 08:22:03 AM 09/10/2020 08:33:36 AM 12
Barbara Name Name
bar#email.com
09/10/2020 08:22:12 AM 09/10/2020 08:31:57 AM 10
Joaquin Name Name Name
joa#email.com
09/10/2020 08:22:12 AM 09/10/2020 08:31:59 AM 10
Rafaella Name Name
raf#email.com
09/10/2020 08:22:18 AM 09/10/2020 08:31:55 AM 10
Andrea Name Name
and#email.com
09/10/2020 08:22:19 AM 09/10/2020 08:32:14 AM 10
Sara Name Name Name
sar#email.com
09/10/2020 08:22:20 AM 09/10/2020 08:31:56 AM 10
If this is posted into a text editor or a Google Sheet it does format into rows and columns correctly.
My code right now takes that long string of info and cuts out anything that is not an email and then checks the email against a class list in order to see who was absent. What I now want to do is to make it check for late students. Ideally the user would input the string and the time class started and it would display absent students and separately late students.
I think the part I can't figure out is how the user can copy paste the info into a prompt or into an html textarea and then correctly write it to rows and columns so I can manipulate the data.
Code:
//this function copies the info to a spreadsheet and sets formulas in order to find just emails and check them against a student list
function checkAttendance() {
var ss = SpreadsheetApp
var sheet = ss.getActiveSheet();
var response = SpreadsheetApp.getUi().prompt("Student Attendance", "Paste emails of students who attended.", SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);
if(response.getSelectedButton() == SpreadsheetApp.getUi().Button.CANCEL) {return}
var responseText = response.getResponseText();
var splitText = responseText.split(" ");
var atHandle = SpreadsheetApp.getActive().getSheetByName("Attendance Handling");
atHandle.getRange(2, 1, 200, 100).clear();
atHandle.getRange(2, 3).setFormula("=FILTER(B2:B, ISNA(MATCH(B2:B, A2:A, 0)))");
var colNum = getColNum2("Student Email");
var rows = sheet.getLastRow();
sheet.getRange(2, colNum, rows-1, 1).copyTo(atHandle.getRange(2, 2, rows, 1));
atHandle.getRange(2, 1).setFormula('=TRANSPOSE(SPLIT(E2, " "))');
atHandle.getRange(2, 4).setFormula('=FILTER(A2:A, ISNA(MATCH(A2:A, B2:B, 0)))')
atHandle.getRange(2, 5).setValue(responseText);
atHandle.getRange(2, 6).setFormula('=if(AND(IFERROR(SEARCH("#", D2), "") <> "", IFERROR(SEARCH("(", D2), "") = ""), D2, "")');
SpreadsheetApp.getActive().getSheetByName("Attendance Handling").getRange(2, 6).copyTo(SpreadsheetApp.getActive().getSheetByName("Attendance Handling").getRange(2, 6, 200, 1));
atHandle.getRange(2, 7).setFormula('=FILTER(F2:F, F2:F <> "")');
showAttendance()
}
function showAttendance() {
var atHandle = SpreadsheetApp.getActive().getSheetByName("Attendance Handling");
var rows1 = getLastRow(3);
var rows2 = getLastRow(7)
var absent = atHandle.getRange(2, 3, rows1-1, 1).getValues().join("\n");
var present = atHandle.getRange(2, 7, rows2-1, 1).getValues().join("\n");
var t = HtmlService.createTemplateFromFile('attendance'); // Modified
t.Absent = absent
t.Present = present
html = t.evaluate().setWidth(600).setHeight(345); // Added
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Class Attendance');
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
//style removed for space
</head>
<body>
<form>
<div>
Absent (in student list but not in pasted values):
<br>
<textarea id="tofield" name="tofield" rows="9" cols="60"><?!= Absent ?></textarea>
<br>
Guests (present in pasted values but not in student list):
<br>
<textarea id="tofield" name="tofield" rows="9" cols="60"><?!= Present ?></textarea>
<br>
<p>
</p>
</form>
Note: this information is not saved. Please use or copy and paste this information as needed beforing closing.
<p>
<button id="btn" style="margin-left: 8px; font-size: 15px; padding: 5px" onclick='google.script.host.close();' class="sbtn btn btn-secondary btn-c">Close</button>
</p>
</body>
</html>
You need to use something like google.script.run.doSomething(data) to pass values from the client-side to the server side code, where doSomething is a server side function and data is a a variable holding the value / object that you want to pass to the client side.
Note: There are some limitations regarding what values/object types can be passed to the server-side, i.e. Date objects can't be passed but you can pase the a string o the correspoining milliseconds.
The following code converts the sample data input into a bidimensional array that can be passed to sheet by using setValues(values).
var data = `Luke Name Name
lr#email.com
09/10/2020 08:22:03 AM 09/10/2020 08:33:36 AM 12
Barbara Name Name
bar#email.com
09/10/2020 08:22:12 AM 09/10/2020 08:31:57 AM 10
Joaquin Name Name Name
joa#email.com
09/10/2020 08:22:12 AM 09/10/2020 08:31:59 AM 10
Rafaella Name Name
raf#email.com
09/10/2020 08:22:18 AM 09/10/2020 08:31:55 AM 10
Andrea Name Name
and#email.com
09/10/2020 08:22:19 AM 09/10/2020 08:32:14 AM 10
Sara Name Name Name
sar#email.com
09/10/2020 08:22:20 AM 09/10/2020 08:31:56 AM 10`;
const arr = data.split('\n');
const matrix = [];
for(let i = 0; i < arr.length;i = i + 3){
var row = [arr[i],arr[i+1],
new Date(arr[i+2].slice(0,22)),
new Date(arr[i+2].slice(24,46)),
arr[i+2].slice(48)]
matrix.push(row);
}
console.info(matrix);
I suggest you to use the above on the server side, as mentioned previously, because Date objects can't be passed from client-side to sever-side, just be sure that the Apps Script, the Spreadsheet and Zoom are using the same timezone, otherwise you will have improve it to handling the timezones differences appropiately.
Resources
Client-to-Server communication | HTML Service | Google Apps Script
You can construct a new Date object from the parsed out times and compare them. If you can get the string representaiotn of the dat you can pass it to the construcotr of Date diruectrly
new Date('December 17, 1995 03:24:00');
Once you have the dates you can use operators to compare them, and determine if the student was late or not.
function isLate(classStart) {
var dateStr = /* get the cell value */
var studentArrvial = Date.parse(dateStr)
return studentArrival - dateStr > 0
}
I'm trying to automate my website by setting predetermined monthly featured videos.
I have JavaScript files already saved w/ the annual data for that particular year - e.g. choose_2017_video.js as well as 2018 & 2019 files. Each image URL text and description text I set in arrays but I can't seem to get them to display. Each array element corresponds to a month [0-11].
The getMonth() method will be the way of retrieving the data.
Somehow, I need to import the song info. into the HTML roughly like this:
<h2 align="center">Video of the month: javascript:song_info[mnth];</h2>
I also need to be able to import the corresponding image path which is saved in a parallel array (of filenames).
var song_info[12], img_URL[12], mnth = today().getMonth();
song_info[7] = "Newsboys - God's Not Dead"; // example data
img_URL[7] = "Newsboys-Gods_Not_Dead_video.JPG";
This site won't let me correctly describe how I'll display the img code using the img_URL element.
Can someone give me examples of how I can import the song information into the h2 code example and img src code?
This might be done a lot easier in an ASP script since I'm more familiar w/ BASIC. JS wasn't even conceived until after I had entered the workforce after a couple yrs. in college.
My intent is to declare new arrays and a pointer variable. The pointer is supposed to determine the month from the current date. One array holds the description of the song while the other holds the filename of the screenshot to be used to launch the YouTube URL in a different browser tab. If I wanted to embed the video, I would just use HTML5 code. It is called by a script src="JSfilename" from an HTML file.
Here is one of the JS files:
var song_info[12], img_URL[12], mnth = today().getMonth();
song_info[0] = "Sidewalk Prophets - Help Me Find It";
song_info[1] = "TobyMac with Kirk Franklin & Mandisa - Lose Your Soul";
song_info[2] = "MercyMe - Dear Younger Me";
song_info[3] = "Kari Jobe - I Am Not Alone";
song_info[4] = "Danny Gokey - Tell Your Heart to Beat Again";
song_info[5] = "Hawk Nelson - Drops In the Ocean";
song_info[6] = "Plumb - Exhale";
song_info[7] = "Newsboys - God's Not Dead";
song_info[8] = "Francesca Battistelli - Holy Spirit";
song_info[9] = "Brandon Heath - Give Me Your Eyes";
song_info[10] = "Matthew West - Strong Enough";
song_info[11] = "Jordan Feliz - The River";
img_URL[0] = "Sidewalk_Prophets-Help_Me_Find_It_video.png";
img_URL[1] = "TobyMac-LoseMySoul_video.png";
img_URL[2] = "MercyMe-DearYoungerMe_video.png";
img_URL[3] = "KariJobe-IAmNotAlone_video.png";
img_URL[4] = "DannyGokey-TellYourHeartToBeatAgain_video3.PNG";
img_URL[5] = "HawkNelson-DropsInTheOcean_video.PNG";
img_URL[6] = "Plumb-Exhale_video.PNG";
img_URL[7] = "Newsboys-Gods_Not_Dead_video.JPG";
img_URL[8] = "FrancescaBattistelli-HolySpirit_video.JPG";
img_URL[9] = "BrandonHeath-GiveMeYourEyes_video.JPG";
img_URL[10] = "Matthew_West-StrongEnough_video.JPG";
img_URL[11] = "JordanFeliz-TheRiver_video.PNG";
So to be clear, you want something like
<h2 align="center">Video of the month: {your_random_video_name_from_your_JSFile}</h2>
So why not just doing this :
<h2 align="center" id="video_name">Video of the month:</h2>
<img src="#" alt="" id="video_preview"/>
<script>
var today = new Date();
var song_info = new Array, img_URL = new Array, mnth = today.getMonth();
song_info[9] = "CHVRCHES - Leave A Trace"; // example data
img_URL[9] = "http://diymag.com/media/img/Artists/C/Chvrches/October-cover/_1500x1000_crop_center-center_75/chvrches-mike-massaro-diy-2015-05.jpg";
song_info[10] = "Newsboys - God's Not Dead"; // example data
img_URL[10] = "Newsboys-Gods_Not_Dead_video.JPG";
document.getElementById("video_name").insertAdjacentHTML('beforeend',song_info[mnth]);
var image = document.getElementById("video_preview");
image.src = img_URL[mnth];
</script>
Example JSFiddle
I have an api that I am using. It returns a list of a store's hours of operations.
I pull this data in php and return it in JSON to be parsed in Javascript.
By looking what is actually returned in chrome's inspect element from my php file that is called, it shows the JSON like this:
[{"lat":"33.1682803","lng":"-117.2198359","hours":"Retail Store\r\nSun: 12pm to 5:30pm\r\nMon: Closed\r\nTues: Closed\r\nWed: 11am to 7pm\r\nThurs: 11am to 8pm\r\nFri: 11am to 8pm\r\nSat: 12pm to 5:30pm\r\n\r\nTasting Room\r\nSun: 12pm to 5pm\r\nMon: Closed\r\nTues: Closed\r\nWed: Closed\r\nThurs: 4pm to 8pm\r\nFri: 4pm to 8pm\r\nSat: 12pm to 5pm","phone":"7605994225","name":"Tap House and Homebrew Shop"}]
AS you can see in the above JSON it keeps the formatting for new lines etc. in the hours.
I then parse my JSON with Javascript to display in HTML 5 like this:
var html = "";
var lat = data[0].lat;
var lng = data[0].lng;
var hours = data[0].hours;
var name = data[0].name;
if(hours == ""){
hours = "N/A";
}
var phone = data[0].phone;
//create hours card
html = "<div class=\"row\"><div class=\"col s12 m6\"><div class=\"card\"> <div class=\"card-content\"><span class=\"card-title black-text\">Hours</span> <p>" + hours +"</p></div><div class=\"card-action\">Navigate<a href=\"tel:"+ phone + "\" style=\"float:right; \">Call</a </div></div></div></div>";
$("#replace").replaceWith(html);
When the hours of operation are displayed they are jumbled together like this instead of on new lines each:
I am using Google Scripts UiApp in order to gather availability information. I want to send this information to a spreadsheet. I have used the example here: http://www.googleappsscript.org/advanced-examples/insert-data-in-sheet-using-ui-forms
to get me started in the right direction.
The Web App looks good and when clicking submit, the appropriate message displays. However, the values that are transferred to the spreadsheet say "undefined" for all of the entries.
How can I convince it to link the textbox entered data to the variables so that I can transfer to the spreadsheet?
Thanks!!
Here is some code:
var submissioSSKey = // Key removed
function doGet() {
var rows = 15
var columns = 15
var mygrid = UiApp.createApplication().setTitle("MLC Walk Ins Scheduling")
var panel = mygrid.createSimplePanel();
// Define the grid layout
var grid = mygrid.createGrid(rows, columns).setCellPadding(2).setCellSpacing(8)
// Create the text at the top
var Title = mygrid.createLabel("Walk-In Scheduling")
grid.setWidget(1, 1, Title)
(snip) - creating various checkboxes and textboxes
var text1 = mygrid.createTextBox().setName('name1')
grid.setWidget(3,9,text1)
var text6 = mygrid.createTextBox().setName('message1')
grid.setWidget(4,9,text6)
// Create the "submit" button
var submit_button = mygrid.createButton("Submit")
grid.setWidget(12,9,submit_button)
var infoLabel = mygrid.createLabel('Availability inserted successfully.').setVisible(false).setId('info');
grid.setWidget(13,9,infoLabel)
var handler = mygrid.createServerClickHandler('insertInSS');
handler.addCallbackElement(panel);
submit_button.addClickHandler(handler);
panel.add(grid);
mygrid.add(panel);
mygrid.add(grid);
return mygrid
}
Then the function call for the button:
//Function to insert data in the sheet on clicking the submit button
function insertInSS(e){
var mygrid = UiApp.getActiveApplication()
var name1 = e.parameter.name1
var message1 = e.parameter.message1
mygrid.getElementById('info').setVisible(true).setStyleAttribute('color','blue')
var sheet = SpreadsheetApp.openById(submissioSSKey).getActiveSheet()
var lastRow = sheet.getLastRow()
var targetRange = sheet.getRange(lastRow+1, 1, 1, 2).setValues([[name1,message1]])
return mygrid
}
Ahh! A simple fix for a big headache.
I had an extra line:
mygrid.add(grid);
that was breaking it.