Send Email from Google sheet as a table without using sheets convertor - email

Please check the spreadsheet below:
spreadsheet
https://docs.google.com/spreadsheets/d/1QFPO4bQfYPM4rRJ_6PYxUrYsFgVeUFx89_nZ1mNaLew/edit#gid=0
The script that I'm currently using is working fine thanks to the posts I've seen here. I just wanted to send it in a better way. I've already checked other posts and I even saw the SheetConverter but is too complicated for me.
Current Result:
https://drive.google.com/file/d/1-OQqnsRwIJaoXOnYZEtPxHy6r3buB8H7/view?usp=sharing
Please check image for the desired result. Thanks!
https://drive.google.com/file/d/1p7cJBTyaZ1ZqI5Jv5WWOGg6_Q-JegfHj/view?usp=sharing

You can create an html table, like this:
function sendEmail(data){
MailApp.sendEmail({
to: "example#mail.com",
subject: "Example",
htmlBody:"<html><body>" + createTable(data)+ "</body></html>"});
}
function createTable(data){
var cells = [];
var table = "<html><body><br><table border=1><tr><th>Start Date</th><th>End Date</th><th>Leave dates</th><th>Status</th></tr>";
for (var i = 0; i < data.length; i++){
cells = data[i].toString().split(",");
table = table + "<tr></tr>";
for (var u = 0; u < cells.length; u++){
table = table + "<td>"+ cells[u] +"</td>";
}
}
table=table+"</table></body></html>";
return table;
}
Supposing you already have the data in a 2D array (rows and columns values).

Related

Send an email everytime data is added into google spreadsheet

I am new to spreadsheets and in need of an Apps Script that triggers an Email every time a row is added, which also gives what has been added(the entire row). I have found many scripts written but none of them work for me.
I finally found a code that works but only partially: The issue is, I do not get data that is pasted in the row (pasting data multiple cells at a time) and data also comes from another automatic source like forms, and does not always enter by a user. in that case, the data comes as undefined. But when I manually enter the data I get the email.
Can anybody help me with this?
function emailChange(e) {
var range = e.range;
var spreadSheet = e.source;
var sheetName = spreadSheet.getActiveSheet().getName();
var spreadsheetName = SpreadsheetApp.getActiveSpreadsheet().getName();
var column = range.getColumn();
var row = range.getRow();
var inputValue = e.value;
var oldValue = e.oldValue;
var user = e.user;
var table = "<table border=1 cellpadding=5px >";
table = table + "<tr><td>File Name</td><td>"+spreadsheetName+"</td></tr>";
table = table + "<tr><td>Sheet Name</td><td>"+sheetName+"</td></tr>";
table = table + "<tr><td>Column</td><td>"+column+"</td></tr>";
table = table + "<tr><td>Row</td><td>"+row+"</td></tr>";
table = table + "<tr><td>Old Value</td><td>"+oldValue+"</td></tr>";
table = table + "<tr><td>Input Value</td><td>"+inputValue+"</td></tr>";
table = table + "<tr><td>User</td><td>"+user+"</td></tr>";
table = table + "<tr><td>Modified</td><td>"+new Date()+"</td></tr>";
table = table + "</table>";
MailApp.sendEmail({
to: "", //Enter Email Address to Send Email
subject: spreadsheetName + " - Change",
htmlBody: table
});
}

Nested Table issue with iText in .net

I use iText 7.0.4.0 with my .net application to generate pdfs. But inner tables overflow when the text is long.
Outer table has 10 columns with green border and seems it has rendered fine as per the image below. Each Outer table cell contains one table with one cell inside it.But Inner Table cell has overflown when the paragraph text is large.
I use iText in a large Forms building product. Hence I've recreated the issue with simple scenario and the code is given below. Please note that the number of columns are not fixed in real usage.
Could anyone please show me the correct path to achieve this?
Here is the C# Code
private Table OuterTable()
{
var columns = GetTableColumnWidth(10);
var outerTable = new Table(columns, true);
outerTable.SetWidthPercent(100);
for (int index = 0; index < columns.Length; index++)
{
Cell outerTableCell = new Cell();
Table innerTable = new Table(new float[] { 100 });
innerTable.SetWidthPercent(100);
Cell innerTableCell = new Cell();
Paragraph paragraph = new Paragraph("ABCDEFGHIJKL").AddStyle(_fieldValueStyle);
innerTableCell.Add(paragraph);
innerTable.AddCell(innerTableCell);
outerTableCell.Add(innerTable);
outerTable.AddCell(outerTableCell);
innerTableCell.SetBorder(new SolidBorder(Color.RED, 2));
innerTableCell.SetBorderRight(new SolidBorder(Color.BLUE, 2));
outerTableCell.SetBorder(new SolidBorder(Color.GREEN, 2));
}
return outerTable;
}
Thanks mkl for spending your valuable time. I solved my issue with your idea of 'no inner tables'. This is not how to solve the issue of nested tables mentioned in the question but another way of achieving the result.
I've used "\n" in the paragraph to achieve what I want. Here is the output and the code.
private Table OuterTable()
{
var columns = GetTableColumnWidth(10);
var outerTable = new Table(columns, true);
outerTable.SetWidthPercent(100);
for (int index = 0; index < columns.Length; index++)
{
Cell outerTableCell = new Cell();
outerTableCell.Add(GetContent());
outerTable.AddCell(outerTableCell);
}
return outerTable;
}
private Paragraph GetContent()
{
int maxIndex = 3;
Paragraph paragraph = new Paragraph();
for (int index = 0; index < maxIndex; index++)
{
paragraph.Add(index + " - ABCDEFGHIJKL \n").AddStyle(_fieldValueStyle);
}
return paragraph;
}

How to add rows to TableView without having any data model

I'm fairly new to javafx, so please bear with me if my question is unclear. I've a TableView which need to be populated using an ObservableList.
The code below populates my "data" with the arraylists generated out of the Map, which in turn is used to add rows to my table.
TableView<ArrayList> table = new TableView<>();
ObservableList<ArrayList> data = FXCollections.observableArrayList();
for(int i=0;i<listSelectedVerticesIds.size();i++){
ArrayList<String> tempString = new ArrayList<>();
for(Map.Entry<String,String> temp2 : mapVertex.get(listSelectedVerticesIds.get(i)).entrySet()){
tempString.add(temp2.getValue());
}
data.add(tempString);
}
table.setItems(data);
However, I do not see the table populated with the list in "data". I'm guessing this is because there is no data binding (using setCellValueFactory). However, as you can see I dont have a data model class. All of my data comes from the Map as strings which I would like to populate in my tableview.
Please suggest.
Here is a simple way to do it that works great. You don't need a data structure to populate a table. You only see that because that's what most examples show. It is an extremely common use case to populate a table from a database or a file. I don't understand why this is so hard to find examples for. Well, hope this helps.
private TableView<ObservableList<StringProperty>> table = new TableView<>();
private ArrayList<String> myList = new ArrayList<>();
private void updateTableRow() {
for (int row = 0; row < numberOfRows; row++) {
ObservableList<StringProperty> data = FXCollections.observableArrayList();
for (int column = 0; column < numberOfColumns; column++) {
data.add(column, new SimpleStringProperty(myList.get(row + (column * numberOfRows))));
}
table.getItems().add(data);
}
}

Reformatting spreadsheet responses into a new tab on form submit

Here are my spreadsheet responses from a form: https://docs.google.com/spreadsheets/d/1a9H2HqAwl29IY6-aCvCKs12Xb3vDcZHCOoNugx81PTA/edit#gid=1939572907
The form data generates in the "raw data" tab of the above spreadsheet. However, I'd like to automatically rearrange the form responses in a different format on the "teacher list" tab of the spreadsheet on form submissions. We are trying to keep track of how often we visit a teacher's room and so want all of the timestamps to appear next to the teacher's name.
I do not know if I should be using formulas or a script to get the job done.
To show you our end goal, I have two form submissions that I have typed into the cells where'd we like them to appear on the "teacher list" tab.
Any suggestions or resources to help me accomplish this would be very much appreciated!
This should give you a good start. And, I have removed the merging of the cells in G column in teacher list tab.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw Data');
var data = sheet.getDataRange().getValues();
var formatSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Teacher List');
var formatData = formatSheet.getDataRange().getValues();
var name = data[sheet.getLastRow()-1][2];
var flag = 0, index;
for(var i=1; i<formatData.length; i++)
{
if(name == formatData[i][0])
{
flag = 1;
index = i;
break;
}
}
if(flag == 1)
{
for(var i=1; i<=5; i++)
{
if(formatData[index][i] == "")
{
formatSheet.getRange(index+1, i+1).setValue(data[sheet.getLastRow()-1][0]);
formatSheet.getRange(index+1, 7).setValue(formatData[index][6].concat('; '+data[sheet.getLastRow()-1][3]));
break;
}
}
}
}
But is there more than 5 visits possible? Is first column of teacher list tab is going to remian same throughout? Do you want to add new row if no match is found for 'Teacher or PLC Observed' from Raw Data with first column of Teacher List tab?
If answer to these questions is positive, you need to tweak a code little bit, try it. I'll help if you're stuck.
Edit: Please set the appscript trigger as: From form -> onSubmit.

Unable to add data in archive table in Entity Framework

I wrote the code to update my table (SecurityQuestionAnswer) with new security password questions and move to old questions to another table (SecurityQuestionAnswersArchives). Total no of security questions is 3. I am able to update the current table, but when I add the same rows to history table, it shows weird data: only two records are added instead of 3 and the data is also duplicated. My code is as follows:
if (oldQuestions.Any())
{
var oldquestionstoarchivelist = new List<SecurityQuestionAnswersArchives>();
var oldquestionstoarchive =new SecurityQuestionAnswersArchives();
for (int i = 0; i < 3; i++)
{
oldquestionstoarchive.Id = oldQuestions[i].Id;
oldquestionstoarchive.SecurityQuestionId = oldQuestions[i].SecurityQuestionId;
oldquestionstoarchive.Answer = oldQuestions[i].Answer;
oldquestionstoarchive.UpdateDate = oldQuestions[i].UpdateDate;
oldquestionstoarchive.IpAddress = oldQuestions[i].IpAddress;
oldquestionstoarchive.SecurityQuestion = oldQuestions[i].SecurityQuestion;
oldquestionstoarchive.User = oldQuestions[i].User;
oldquestionstoarchivelist.Add(oldquestionstoarchive);
}
user.SecurityQuestionAnswersArchives = oldquestionstoarchivelist;
//await Store.UpdateAsync(user);
_dbContext.ArchiveSecurityQuestionAnswers.AddRange(oldquestionstoarchivelist);
_dbContext.SecurityQuestionAnswers.RemoveRange(oldQuestions);
await _dbContext.SaveChangesAsync();
oldquestionstoarchivelist.Clear();
}
UPDATE 1
The loop looks fine, It iterates three times(0,1,2), which is expected. First issue is with AddRange function to which I was passing a list , but it takes an IEnumerable input, I rectified it using following code.
IEnumerable<SecurityQuestionAnswersArchives> finalArchiveses = oldquestionstoarchivelist;
_dbContext.ArchiveSecurityQuestionAnswers.AddRange(finalArchiveses);
The other issue is duplicate data , which I am unable to figure out where the issue is. Please help me in finding this out.
Your help is much appreciated !
Got it ! Just sharing in case anybody has same issue.
The problem was with initialization at wrong place. I moved
var oldquestionstoarchive =new SecurityQuestionAnswersArchives();
in side the Forloop, now the variable will hold the unique values over each iteration.
var oldquestionstoarchivelist = new List<SecurityQuestionAnswersArchives>();
for (int i = 0; i < 3; i++)
{
var oldquestionstoarchive = new SecurityQuestionAnswersArchives();
oldquestionstoarchive.SecurityQuestionId = oldQuestions[i].SecurityQuestionId;
oldquestionstoarchive.Answer = oldQuestions[i].Answer;
oldquestionstoarchive.UpdateDate = oldQuestions[i].UpdateDate;
oldquestionstoarchive.IpAddress = oldQuestions[i].IpAddress;
oldquestionstoarchive.SecurityQuestion = oldQuestions[i].SecurityQuestion;
oldquestionstoarchive.User = oldQuestions[i].User;
oldquestionstoarchivelist.Add(oldquestionstoarchive);
}