upload files into google drive folder from side bar UI - html

I am trying to make web app as a sidebar in spreadsheet using HTML5, Bootstrap 5 & JavaScript to make entry of data easier . I managed to go through the entire process But the problem that I can't make the button upload files into google drive folder and return with the url back.
the link of sheet working with.
I think the problem in this variable from html script but I don't know what is it
var url = document.getElementById("transaction-file").addEventListener('click',
function(a){
google.script.run.uploadFiles(this.parentNode)
});
https://docs.google.com/spreadsheets/d/1D-tEPsUJqGbCHrF8CYQlPu_ZhmVIGDYEojHfO0_7rW4/edit?usp=sharing
google script code
function loadForm() {
const htmlForSidebar = HtmlService.createTemplateFromFile("uform");
const htmlOutput = htmlForSidebar.evaluate();
htmlOutput.setTitle("Winter 2021");
const ui = SpreadsheetApp.getUi();
ui.showSidebar(htmlOutput);
}
function createMenu(){
const ui = SpreadsheetApp.getUi();
const menu = ui.createMenu("My Forms");
menu.addItem("Show UserForm", "loadForm");
menu.addToUi();
}
function onOpen(){
createMenu();
}
function uploadFiles(files){
var file = files.myFile;
var folder = DriveApp.getFolderById('1gaNAb1s8j7wmotvRUJbg4yfJOFNdZYo5');
var createFile = folder.createFile(file);
return createFile.geturl();
}
function addNewRow(rowData) {
const currentDate = new Date();
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Sheet1");
ws.appendRow([currentDate, rowData.trxDate, rowData.account, rowData.trxID, rowData.amount, rowData.url, rowData.comment]);
return true;
}
function getDropDownArray(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const ws = ss.getSheetByName("Ref");
return ws.getRange(2, 1, ws.getLastRow()-1, 1).getValues();
}
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<div class="container pt-3">
<h4 class="border-bottom pb-2 mb-4">Donations' Registration <span class="badge bg-secondary">Form</span></h4>
<div id="userform">
<div class="mb-3">
<label for="transaction-date" class="form-label">Transaction Date</label>
<input type="date" class="form-control" id="transaction-date" required>
<div class="invalid-feedback">Please enter valid date.</div>
</div>
<div class="mb-3">
<label for="transaction-account" class="form-label">Account</label>
<select class="form-select" id="transaction-account" required aria-label="select account" required>
</select>
<div class="invalid-feedback">Please enter valid account.</div>
</div>
<div class="mb-3">
<label for="transaction-id" class="form-label">Transaction ID</label>
<input type="text" class="form-control" id="transaction-id" required>
<div class="invalid-feedback">Please enter valid ID.</div>
</div>
<div class="mb-3">
<label for="transaction-amount" class="form-label">Amount</label>
<input type="number" class="form-control" id="transaction-amount" required>
<div class="invalid-feedback">Please enter valid amount without any service fees.</div>
</div>
<div class="mb-3">
<label for="transaction-file" class="form-label">url</label>
<input type="file" class="form-control" id="transaction-file" name="myFile" aria-label="file example" required>
<div class="invalid-feedback">Please upload right file.</div>
</div>
<div class="mb-3">
<label for="transaction-memo" class="form-label">Memo</label>
<textarea class="form-control" id="transaction-memo" rows="1"></textarea>
</div>
<div class="mb-3">
<button class="btn btn-primary" id="mainButton">Add to Database</button>
</div>
</div>
</div>
<!-- Optional JavaScript; choose one of the two! -->
<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<!-- Option 2: Separate Popper and Bootstrap JS -->
<!--
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
-->
<script>
function afterButtonClicked(){
if(validate()){
var trxDate = document.getElementById("transaction-date");
var account = document.getElementById("transaction-account");
var trxID = document.getElementById("transaction-id");
var amount = document.getElementById("transaction-amount");
var url = document.getElementById("transaction-file");
var comment = document.getElementById("transaction-memo");
var rowData = {trxDate: trxDate.value, account: account.value, trxID: trxID.value, amount: amount.value, url: url.value, comment: comment.value};
google.script.run.withSuccessHandler(afterSubmit).addNewRow(rowData);
} else {
//handle this later
}
}
function afterSubmit(e){
clearFields(["transaction-date", "transaction-account", "transaction-id", "transaction-amount", "transaction-file", "transaction-memo"]);
}
function clearFields(fields){
fields.forEach(function(field){
var el = document.getElementById(field);
el.value = "";
});
}
function validate(){
var fieldsToValidate = document.querySelectorAll("#userform input, #userform select");
//is-invalid
Array.prototype.forEach.call(fieldsToValidate,function(el){
if(el.checkValidity()){
el.classList.remove("is-invalid");
} else {
el.classList.add("is-invalid");
}
});
return Array.prototype.every.call(fieldsToValidate,function(el){
return el.checkValidity();
});
}
function afterSidebarLoads(){
google.script.run.withSuccessHandler(afterDropDownArrayReturned).getDropDownArray();
}
function afterDropDownArrayReturned(arrayOfArrays){
var account = document.getElementById("transaction-account");
arrayOfArrays.forEach(function(r){
var option = document.createElement("option");
option.textContent = r[0];
account.appendChild(option);
});
}
document.getElementById("mainButton").addEventListener("click",afterButtonClicked);
google.script.run.uploadFiles(this.parentNode);
document.addEventListener("DOMContentLoaded",afterSidebarLoads);
</script>
</body>
</html>

Related

Google Web App - Search box to filter the data from Google Spread sheet

Thanks in advance. Just to start with, I am not a coder, but I keep on researching. I made a search Web App to filter the data from Google spreadsheet which has more than 2000+ rows, which keeps on increasing day by day and around 135 columns for different Institutes. So, it was messy to search in that Google sheet, and hence I created this web app.
Everything is working smoothly until the records were around 1200 rows but now I am facing an issue to display more than 2000 records. The Web App Search box displays the list based on the key we pressed. Like if we enter "A", it will display the names starting from the alphabet "A". So, what I do is, I keep on adding the new tags (Institute names) and it works well but now suddenly after adding few records, it says unable to open the file.
Request you to please look into this and let me know any alternative or correct this code to work smoothly regardless of the numbers of tags or rows. Thank you so much.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>
<!-- <link href="path/to/select2.min.css" rel="stylesheet" />
<script src="path/to/select2.min.js"></script> -->
<!-- <link href="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2#4.1.0-rc.0/dist/js/select2.min.js"></script> -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Autocomplete using Jquery</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.
css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<!--##JAVASCRIPT FUNCTIONS ---------------------------------------------------- -->
<script type="text/javascript">
$( function() {
var searchtext = [
"Australian Catholic University",
"Australian National University (ANU)",
"Central Queensland University",
"Royal Melbourne Institute of Technology (RMIT)",
/*Like this we have more that 2000 names of Institutes*/
];
$( "#searchtext" ).autocomplete({
source: searchtext
/* #the tags is the id of the input element
source: tags is the list of available tags*/
});
} );
//PREVENT FORMS FROM SUBMITTING / PREVENT DEFAULT BEHAVIOUR
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener("load", preventFormSubmit, true);
// $(document).ready(function() {
// $('.js-example-basic-single').select2();
// });
function myFunction() {
document.getElementById("searchtext").size = "70";
}
//HANDLE FORM SUBMISSION
function handleFormSubmit(formObject) {
google.script.run.withSuccessHandler(createTable).processForm(formObject);
// document.getElementById("search-form").reset();
}
//CREATE THE DATA TABLE
function createTable(dataArray) {
if(dataArray && dataArray !== undefined && dataArray.length != 0){
var result = "<table class='table table-sm table-striped' id='dtable' style='font-size:0.8em'>"+
"<thead style='white-space: nowrap'>"+
"<tr>"+ //Table headings
"<th scope='col'>Institution</th>"+
"<th scope='col'>Agreement with</th>"+
"<th scope='col'>Type of institution</th>"+
"<th scope='col'>Country</th>"+
/*Around 100+ Columns are there*/
"</thead>";
for(var i=0; i<dataArray.length; i++) {
result += "<tr>";
for(var j=0; j<dataArray[i].length; j++){
result += "<td>"+dataArray[i][j]+"</td>";
}
result += "</tr>";
}
result += "</table>";
var div = document.getElementById('search-results');
div.innerHTML = result;
}else{
var div = document.getElementById('search-results');
//div.empty()
div.innerHTML = "Data not found!";
}
}
</script>
<!--##JAVASCRIPT FUNCTIONS ~ END ---------------------------------------------------- -->
</head>
<body style="background-color:#cdffcd;">
<h1 align="center"><img src="https://drive.google.com/uc?export=download&id=16SqA92JMCD3AVWH07BeyPPLlEBaO_4Ae" alt="logo" width="120" height="100"/> The SoT Search Form</h1>
<div class="container">
<br>
<div class="row">
<div class="col">
<!-- ## SEARCH FORM ------------------------------------------------ -->
<form id="search-form" class="form-inline" onsubmit="handleFormSubmit(this)" action="/action_page.php" method="get">
<div class="form-group mb-2">
<label for="searchtext" align="center"><strong>Search for the provider</strong></label>
</div>
<div class="form-group mx-sm-3 mb-2">
<input id="searchtext" name="searchtext" class="form-control" onclick="myFunction()" placeholder="Enter the name.." align="center">
<!-- On keyup calls the function everytime a key is released -->
</div>
<button type="submit" class="btn btn-primary mb-2">Search</button>
<input type="reset" class="btn btn-primary mb-2" id="resetbutton" style='margin-left:16px' value="Reset">
</form>
<!-- ## SEARCH FORM ~ END ------------------------------------------- -->
</div>
</div>
<div class="row">
<div class="col">
<!-- ## TABLE OF SEARCH RESULTS ------------------------------------------------ -->
<div id="search-results" class="table-responsive">
<!-- The Data Table is inserted here by JavaScript -->
</div>
<!-- ## TABLE OF SEARCH RESULTS ~ END ------------------------------------------------ -->
</div>
</div>
</div>
</body>
</html>
============= Code File===========================================
function doGet() {
return HtmlService.createTemplateFromFile('Index').evaluate();
}
/* PROCESS FORM */
function processForm(formObject){
var result = "";
if(formObject.searchtext){//Execute if form passes search text
result = search(formObject.searchtext);
}
return result;
}
//SEARCH FOR MATCHED CONTENTS
function search(searchtext){
var spreadsheetId = 'xxxxxxx';
var dataRage = 'ABC!A2:DV1500';
var data = Sheets.Spreadsheets.Values.get(spreadsheetId, dataRage).values;
var ar = [];
data.forEach(function(f) {
if (~f.indexOf(searchtext)) {
ar.push(f);
}
});
return ar;
}

Loading the arrays from server when DOMContentLoaded

I try to get the contents of 3 arrays from spreadsheet in 3 vars when the page is loaded in DOMContentLoaded. But I get nothing (look the picture)
I deployed the test project here: https://script.google.com/a/fmlogistic.com/macros/s/AKfycbxROleHY3u69jTpdVZjLOfDTzY9c5q1S4kwm0ctTFzU/dev
and test-spreadsheet with script of this is here
https://docs.google.com/spreadsheets/d/1qxr91eiLUykfLS0zKq3D4Dn206vnEkVqxDo6ZQF1rU4/edit#gid=0
I tried to write something like here, but this way with variantes Apps script return values from server function to html form
const inputs = document.querySelector('.dws-input');
const formControl = document.querySelectorAll('.form-control');
let findData;
let curInpID;
let firstValid, secValid, thirdValid, allValid;
formControl[0].focus();
function callBack(e) {
var Logs = e.ListLogins;
var Tabs = e.ListTables;
var Ords = e.ListOrders;
}
document.addEventListener("DOMContentLoaded", function(){
google.script.run.withSuccessHandler(callBack).sendData();
var Logs = e.ListLogins;
var Tabs = e.ListTables;
var Ords = e.ListOrders;
console.log(Logs);
console.log(Tabs);
console.log(Ords);
});
<!doctype html>
<html lang="en">
<head>
<title>CLR: PACKING</title>
<meta charset = "UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<div class="conteiner">
<form novalidate>
<h6 class="title">PACKING</h6>
<div class="dws-input">
<div class="col-md-3"></div>
<div>
<div class="form-floating mb-3 mt-3">
<input type="text" class="form-control" novalidate id="tLogin" name= "username" placeholder= "Login:" autofocus >
<label for="tLogin">Login:</label>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" class="form-control" novalidate id="tTable" name= "text" placeholder= "Table:" >
<label for="tTable">Table:</label>
</div>
</div>
<div class="form-floating mb-3 mt-3">
<input type="text" novalidate class="form-control" id="tOrder" name= "text" placeholder= "Order:" >
<label for="tOrder">Order:</label>
</div>
</div>
</form>
</div>
<?!= include("index-js"); ?>
</body>
</html>
In actions.gs at server I wrote this:
const url = SpreadsheetApp.getActiveSpreadsheet().getUrl();
var htmlServ = HtmlService.createTemplateFromFile("index");
let ss = SpreadsheetApp.openByUrl(url);
let sheetTo = ss.getSheetByName("#sistem");
let sheetIn = ss.getSheetByName("#packing");
function doGet(e){
return htmlServ.evaluate();
}
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
function sendData(){
var lrLogins = sheetTo.getRange("A:A").getValues().filter(String).length;
var arrLogins = sheetTo.getRange(1, 1, lrLogins, 1).getValues().flat();
var lrTMPLORDS = sheetTo.getRange("K:K").getValues().filter(String).length;
var curTMPLORDS = sheetTo.getRange(1, 11, lrTMPLORDS, 1).getValues();
var lrTABLES = sheetTo.getRange("R:R").getValues().filter(String).length;
var curTABLES = sheetTo.getRange(1, 18, lrTABLES, 1).getValues().flat();
var objDataInfo = {};
objDataInfo.ListLogins = arrLogins;
objDataInfo.ListTables = curTABLES;
objDataInfo.ListOrders = curTMPLORDS;
return objDataInfo;
}
Are there any ways to get the contents of these arrays when the page is loaded
Try this:
function callBack(e) {
var Logs = e.ListLogins;
var Tabs = e.ListTables;
var Ords = e.ListOrders;
console.log(Logs);
console.log(Tabs);
console.log(Ords);
}
document.addEventListener("DOMContentLoaded", function(){
google.script.run.withSuccessHandler(callBack).sendData();
//the following code is not in the callback function and it get's executed probably before the callback is returned.
var Logs = e.ListLogins;
var Tabs = e.ListTables;
var Ords = e.ListOrders;
console.log(Logs);
console.log(Tabs);
console.log(Ords);
});
It could have been written like this:
document.addEventListener("DOMContentLoaded", function () {
google.script.run.withSuccessHandler(function(e){
var Logs = e.ListLogins;
var Tabs = e.ListTables;
var Ords = e.ListOrders;
console.log(Logs);
console.log(Tabs);
console.log(Ords);
}).sendData();
});

Apps Script: Collect Form Input and Display Today's Total

First time poster here: I've created a web app in Apps Script where the user enters:
Date
Food
Quantity
...then the associated 'health points' are calculated and added to a spreadsheet in Google Sheets.
What I want to do is calculate and display the day's total and then recalculate and display whenever the form is submitted. I'm still a newer JS user, so I'm cheating a bit by calculating in Google Sheets. Here's what that formula looks like:
=sum(ArrayFormula(if(today()-1=Data!A:A,Data!B:B,0)))
..then I'm passing that as a template value. That works when loading the page, but I would like it to update whenever the form is submitted.
Do you have ideas on how to calculate today's total using a script instead of Sheets and recalculating/displaying when the form is submitted?
Update: I've attached the code. And here's the sheet: https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit?usp=sharing
function doGet(request) {
var t = HtmlService.createTemplateFromFile('index');
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Points");
var total = ws.getRange(1,1,1,1).getValue();
var remaining = 25-total;
Logger.log(total);
Logger.log(remaining);
t.total = total;
t.remaining = remaining;
return t.evaluate();
}
function getLast() {
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Data");
var last = ws.getLastRow();
Logger.log(last);
}
/* #Include JavaScript and CSS Files */
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
/* #Process Form */
function processForm(formObject) {
// (Calories * .0305) + (Sat Fat * .275) + (Sugar * .12) - (Protein * .098)
var smartpointsServing = Math.round((formObject.calories * .0305) + (formObject.satfat * .275) + (formObject.sugar * .12) - (formObject.protein * .098));
// var formattedDate = Utilities.formatDate(new Date(formObject.today), "GMT-6", "MM/dd/yyyy");
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Foods");
var ws2 = ss.getSheetByName("Data");
var newFoodHp = smartpointsServing*formObject.quantity;
if (formObject.new_food_name !== ""){
ws.appendRow([formObject.new_food_name,
smartpointsServing,
formObject.serving_size_no,
formObject.serving_size_unit,
formObject.calories,
formObject.satfat,
formObject.sugar,
formObject.protein]);
ws2.appendRow([formObject.today,
newFoodHp,
formObject.food_name,
formObject.quantity]);}
else {
ws2.appendRow([formObject.today,
formObject.smartpoints,
formObject.food_name,
formObject.quantity]);
}
}
function getSmartPoints(foodLookup){
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Foods");
var data = ws.getRange(2, 1, ws.getLastRow()-1, 2).getValues();
var foodList = data.map(function(r){ return r[0]; });
var smartpointsPerServing = data.map(function(r){ return r[1]; });
var position = foodList.indexOf(foodLookup);
if (position >-1){
return smartpointsPerServing[position];
} else {
return 'Food Not Found';
}
}
function returnDropDownArray() {
var url = "https://docs.google.com/spreadsheets/d/1pXtOAnVJOkz1DGKir79pxoMUG85LPSfoN4SSVUk0a1k/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Foods");
var array = ws.getRange(2,1,ws.getLastRow()-1,1).getValues().sort();
Logger.log(array);
return ws.getRange(2,1,ws.getLastRow()-1,1).getValues().sort();
}
<!DOCTYPE html>
<html>
<head>
<!--Install Bootstrap-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<?!= include('JavaScript'); ?>
<style>
body {
color: blue;
}
</style>
</head>
<body>
<p id="date"></p>
<div class="container">
<form id="myForm" onsubmit="handleFormSubmit(this)">
<h1><b>Health Points</b></h1>
<div class = "row">
<div class="col-md-2">
<label for="today">Date</label>
<input type="date" class="form-control" id="today" name="today" required>
</div>
</div>
<div class="row">
<div class="col-md-3">
<label for="food_name">Food Name:</label><br>
<select class="form-control" id="food_name" name="food_name" value="Select Food" required>
</select>
</div>
<div class="col-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="add" name="add">
<label class="form-check-label" for="flexCheckDefault">
Add New Food?
</label>
</div>
</div></div>
<div class="row">
<div class="col-md-4">
<label for="quantity">Quantity:</label><br>
<input id="quantity" type="number" step=".5" value="1" name="quantity">
</div>
</div><br>
<div class="row">
<div class="col-md-4">
<input id="smartpoints" type="text" placeholder="Health Points" name="smartpoints" readonly>
</div>
</div>
<!-- <br>
<div id="templateTotal"><p>Today's Total: <strong><?= total ?>/25</strong><br>
Points Remaining: <strong><?= remaining ?></strong></p></div> -->
<!-- Start section for adding foods -->
<div id="addfood" style="display:none;">
<br>
<div class="col-md-6">
<div class="card">
<div class="card-header">
Add a Food
</div>
<div class="container">
<div class="row">
<div class="col-md-4">
<label for="new_food_name">New Food Name:</label><br>
<input type="text" id="new_food_name" name="new_food_name">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="serving_size_no">Serving Size #:</label>
<input type="number" id="serving_size_no" name="serving_size_no" step=".25">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="serving_size_unit">Serving Size Unit:</label>
<input list="serving_size_unit_list" id="serving_size_unit" name="serving_size_unit">
<datalist id="serving_size_unit_list">
<option value="Cup(s)">
<option value="Ounce(s)">
<option value="Tbsp(s)">
<option value="Tsp(s)">
<option value="Gram(s)">
</datalist>
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="calories">Calories:</label>
<input type="number" id="calories" name="calories" step="1">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="satfat">Saturated Fat:</label>
<input type="number" id="satfat" name="satfat">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="satfat">Sugar:</label>
<input type="number" id="sugar" name="sugar">
</div>
</div>
<div class="row">
<div class="col-md-4">
<label for="protein">Protein:</label>
<input type="number" id="protein" name="protein">
</div>
</div><br>
</div>
</div>
</div></div><br>
<!-- End section for adding foods -->
<div class="col-md-4">
<button type="submit" class="btn btn-primary btn-block">Submit</button>
</div>
</form>
<div id="output"></div>
</div>
<script type="text/javascript">
document.getElementById("add").onchange = function(){
if (document.getElementById("add").checked) {
addfood.style.display = "block";
} else {
addfood.style.display = "none";
}
};
document.getElementById('food_name').onclick = function() {
var foodLookup = this.value;
google.script.run.withSuccessHandler(populateSmartpoints).getSmartPoints(foodLookup);
function populateSmartpoints(smartpointsPerServing){
var quantity = document.getElementById('quantity').value;
document.getElementById('smartpoints').value=smartpointsPerServing*quantity;
};
}
// Run function afterPageLoads once the page has loaded
document.addEventListener("DOMContentLoaded",afterPageLoads);
// Get drop down array for food names if that function is successful
function afterPageLoads() {
google.script.run.withSuccessHandler(afterDropDownArrayReturned).returnDropDownArray();
}
// Populate food name drop down with array from Google Sheets
function afterDropDownArrayReturned(arrayOfArrays) {
var item = document.getElementById("food_name");
console.log(item);
arrayOfArrays.forEach(function(r){
var option = document.createElement("option");
option.textContent = r[0];
item.appendChild(option);
});
}
// Update Smart Points if quantity is updated
document.getElementById('quantity').onchange = function() {
var sp = document.getElementById('smartpoints').value;
var quantity = document.getElementById('quantity').value;
document.getElementById('smartpoints').value=sp*quantity;
}
// Update food name if new food is added
document.getElementById('new_food_name').onchange = function() {
var newOption = document.getElementById('new_food_name').value;
if (newOption !==""){
var item = document.getElementById("food_name");
var option = document.createElement("option");
option.textContent = newOption;
item.appendChild(option);
var val = item.value;
item.value = newOption;
}
}
//Set today as the default date
n = new Date();
y = n.getFullYear();
m = n.getMonth() + 1;
d = n.getDate();
document.getElementById("today").value = y + "-" + m + "-" + d;
//Reload Page
</script>
</body>
</html>
This will sum column B in a linked sheet to a form from row 2 to the submitted row.
function onFormSubmit(e) {
const sh=e.range.getSheet();
const vals=sh.getRange(2,2,e.range.getRow()-1).getValues().flat();
let sum=vals.reduce(function(a,c){return a+=c;},0);
Logger.log(sum);
}
Remember the trigger requires an installable trigger.

Are the csv files generated with parseCsv stored somewhere?

I'm doing a web in google script.
I have done the following search method:
https://script.google.com/macros/s/AKfycbzxWqtu9bIhTXb2zP9fsOoFFqe3St1T1C91ZDVu747GCWxrR1c/exec
my code Codigo.gs is:
function doGet(e) {
Logger.log(Utilities.jsonStringify(e));
if(!e.parameter.page){
return HtmlService.createTemplateFromFile("Index").evaluate();
}
var template=HtmlService.createTemplateFromFile(e.parameter.page)
template.action=ScriptApp.getService().getUrl();
return template.evaluate();
return HtmlService
.createHtmlOutputFromFile('Index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
/***************************** buscar asignado de trabajo ********************************************/
function get_AsignadoSS(k){
var sPers_asignado=k.pers_asignado;
var sReg_Asig="LIMA";
var contenido_ul="";
var spreadsheetId_r = '1ykYOd5PWP5aZEREnRIqkPMLT1pSYrcRA6mfQHl7bL4I'; // Please set the spreadsheet ID.
var targetSheet_r = 'Personal'; // Please set the sheet name.
if(sPers_asignado!="") {
var query_r = 'select A, B where ( B contains "'+sPers_asignado.toUpperCase()+'" or A contains "'+sPers_asignado.toUpperCase()+'" ) AND E = "'+sReg_Asig+'"'; // Please set the query for retrieving the values.
var ss_r = SpreadsheetApp.openById(spreadsheetId_r);
var sheetId_r = ss_r.getSheetByName(targetSheet_r).getSheetId();
var url_r = "https://docs.google.com/spreadsheets/d/" + spreadsheetId_r + "/gviz/tq?gid=" + sheetId_r + "&tqx=out:csv&tq=" + encodeURIComponent(query_r);
var res_r = UrlFetchApp.fetch(url_r, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
var row = Utilities.parseCsv(res_r.getContentText());
//https://docs.google.com/spreadsheets/d/1z4izqpus1yE6rZiqY1ttCEYA3NO3d7J3bZ4oFgQW330/gviz/tq?gid=Usuarios&tqx=out:csv&tq=encodeURIComponent('select A, B where ( B contains "li" )')
if(row.length>6){
var maximo=7;
}else{
var maximo=row.length;
}
//var contenido_ul=sCodigo_site;
var contenido_ul=contenido_ul+"<ul id='country-list' class='list-group'>";
for (var i = 1; i < maximo; i++) {
var nombre_site = row[i][1].toString();
var pasar_nom_site='"'+row[i][1].toString()+'"';
var contenido_ul=contenido_ul+"<li class='list-group-item' style='text-align: left' onClick='selectCountry("+pasar_nom_site+");'>"+nombre_site+"</li>";
}
var contenido_ul=contenido_ul+"</ul>";
}
if(sPers_asignado=="") {
var contenido_ul="";
}
return contenido_ul;
}
and my code Index.html is
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script>
function buscar_asignado(){
google.script.run.withSuccessHandler(get_Asignado).get_AsignadoSS(document.forms[0]);
}
function get_Asignado(data){
//alert("tt");
$("#suggesstion-box-asignado").show();
$("#suggesstion-box-asignado").html(data);
}
function selectCountry(codigo) {
$("#pers_asignado").val(codigo);
$("#suggesstion-box-asignado").hide();
}
/*----------------codigo esencial para conectar con codigo.GS----------------------*/
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
</script>
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.datatables.net/responsive/2.2.3/css/responsive.bootstrap4.min.css">
<link rel="stylesheet" href="https://cdn.datatables.net/fixedheader/3.1.6/css/fixedHeader.dataTables.min.css">
</head>
<body>
<div class="modal-header" style="background-color: red;color: white;padding-top:5px;padding-bottom:5px">
<CENTER><label style="font-size: 30px;font-family: monospace;font-weight: normal;color:white">ACTIVIDADES</label></CENTER>
</div>
<div id="todo_contenido"style="display:block">
<center><br><br>
<div class="modal-content" style="width:95%">
<div class="modal-body">
<form id="datosTrabajo" name="datosTrabajo">
<div class="form-group row">
<label for="pers_asignado" class="col-sm-2 col-form-label">Asignado:</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="pers_asignado" name="pers_asignado" onkeyup="buscar_asignado();" placeholder="Nombre Asignado..." style="background-color: white">
<div id="suggesstion-box-asignado" style="position: absolute;z-index: 1"></div>
</div>
<label for="tipo_trabajo" class="col-sm-2 col-form-label">Tipo Trabajo:</label>
<div class="col-sm-4">
<select class="form-control" id="tipo_trabajo" name="tipo_trabajo" >
<option value="">Select Tipo Equipo:</option>
<option value="ATPs">ATPs</option>
<option value="Caceria Interferencia">Caceria Interferencia</option>
<option value="Desbalance RTWP">Desbalance RTWP</option>
<option value="Respaldo Baterias">Respaldo Baterias</option>
<option value="Site Audit">Site Audit</option>
<option value="Trabajos TX">Trabajos TX</option>
<option value="Prueba de Llamadas">Prueba de Llamadas</option>
<option value="PIM Logico">PIM Logico</option>
<option value="Administrativo">Administrativo</option>
<option value="OTROS">OTROS</option>
</select>
</div>
</div>
</form>
</div>
</div>
<br>
</center>
</div>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdn.datatables.net/1.10.20/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.20/js/dataTables.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/responsive.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/fixedheader/3.1.6/js/dataTables.fixedHeader.min.js"></script>
</body>
</html>
Then each time a letter is entered, a new search is made. In this case the search becomes normal, since it only occurs in 100 records. But my question is whether it is every time a new query is made (every time a digit is entered). These csv files are stored somewhere. The problem I have is that I have a more extensive code, which searches 6000 records; but you are not doing the search, and there are personnel who connect to this website to enter information and are having problems.
Or will there be some other way to do this type of search in Google Script?
parseCsv() - Returns a tabular 2D array representation of a CSV string. So
var A=Utilities.parseCsv(csvdata);
sheet.getRange(1,1,A.length,A[0].length).setValues(A);
will put the data into sheet.
The csv and the 2d array's are not stored anywhere unless you stored somewhere.

Collect receipt data from users with Google Form and save in Google Sheets

I would like to create a script to receive expense receipts in a Google drive, and log details provided by a Google Form (date, vendor, amount, and picture of the receipt...)
I've tried to replicate the script and html from How do I rename files uploaded to an apps script web app form?, and end up with error 400 with no details...
Also tried to merge Amit Agarwal's script
https://www.labnol.org/internet/receive-files-in-google-drive/19697/
with https://github.com/dwyl/learn-to-send-email-via-google-script-html-no-server
Second example logs entries into google sheets, but also sends email : Perfect! Amit's example allows to create named folders and I can rename the file with some additionnal code, love it!
But in my try to merge both, I end up with two buttons at the bottom of the form... one sends the rows, the other sends the file! :D
Here's my actual script.gs
// if you want to store your email server-side (hidden), uncomment the next line
//var TO_ADDRESS = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('index.html').setTitle("envoyez vos pièces jointes");
}
// this is from Amit Agarwal's example
function uploadFileToGoogleDrive(data, file, prenom, nom) {
try {
var dropbox = "Justificatifs reçus";
var folder, folders = DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(dropbox);
}
var contentType = data.substring(5,data.indexOf(';')),
bytes = Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)),
blob = Utilities.newBlob(bytes, contentType, file),
file = folder.createFolder([prenom, nom].join(" ")).createFile(blob);
//this is an addition i've made to rename the files upon submission, used to work in previous tries, but now gives "null null.pdf'
//var newFileName = [prenom +'_'+ nom +".pdf"];
//file.setName(newFileName);
return "OK";
} catch (f) {
return f.toString();
}
}
// Here stops Amit Agarwal's script, below is the following of
//https://github.com/dwyl/learn-to-send-email-via-google-script-html-no-server
function formatMailBody(obj, order) {
var result = "";
if (!order) {
order = Object.keys(obj);
}
// loop over all keys in the ordered form data
for (var idx in order) {
var key = order[idx];
result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
// for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value,
// and append it to the `result` string created at the start.
}
return result; // once the looping is done, `result` will be one long string to put in the email body
}
// sanitize content from the user - trust no one
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
var placeholder = HtmlService.createHtmlOutput(" ");
placeholder.appendUntrusted(rawInput);
return placeholder.getContent();
}
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
// names and order of form elements (if set)
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
// send email if to address is set
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "Contact form submitted",
// replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService // return json success results
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* record_data inserts the data received from the html form submission
* e is the data received from the POST
*/
function record_data(e) {
var lock = LockService.getDocumentLock();
lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
try {
Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
// select the 'responses' sheet by default
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = e.parameters.formGoogleSheetName || "responses";
var sheet = doc.getSheetByName(sheetName);
var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var newHeader = oldHeader.slice();
var fieldsFromForm = getDataColumns(e.parameters);
var row = [new Date()]; // first element in the row should always be a timestamp
// loop through the header columns
for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
var field = oldHeader[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
// mark as stored by removing from form fields
var formIndex = fieldsFromForm.indexOf(field);
if (formIndex > -1) {
fieldsFromForm.splice(formIndex, 1);
}
}
// set any new fields in our form
for (var i = 0; i < fieldsFromForm.length; i++) {
var field = fieldsFromForm[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
newHeader.push(field);
}
// more efficient to set values as [][] array than individually
var nextRow = sheet.getLastRow() + 1; // get next row
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// update header row with any new data
if (newHeader.length > oldHeader.length) {
sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
}
}
catch(error) {
Logger.log(error);
}
finally {
lock.releaseLock();
return;
}
}
function getDataColumns(data) {
return Object.keys(data).filter(function(column) {
return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
});
}
function getFieldFromData(field, data) {
var values = data[field] || '';
var output = values.join ? values.join(', ') : values;
return output;
}
And here's the index.html
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Envoyez vos justificatifs</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css">
<style>
.disclaimer{width: 480px; color:#646464;margin:20px auto;padding:0 16px;text-align:center;font:400 12px Roboto,Helvetica,Arial,sans-serif}.disclaimer a{color:#009688}#credit{display:none}
</style>
</head>
<!-- START HERE -->
<link rel="stylesheet" href="https://unpkg.com/purecss#1.0.0/build/pure-min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<!-- Style The Contact Form How Ever You Prefer -->
<link rel="stylesheet" href="style.css">
<form class="gform pure-form pure-form-stacked" method="POST" data-email="example#email.net"
action="https://script.google.com/macros/s/AKfycbzSlohhLp27NcnG8lBt13GUm4PblUMTL9uU1CTgcOBohz1iH0k/exec"
id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
<div id="forminner">
<div class="row">
<div class="col s12">
<h5 class="center-align teal-text">Envoyez vos justificatifs</h5>
<p class="disclaimer">This File Upload Form (tutorial) is powered by Google Scripts</p>
</div>
</div>
<fieldset class="pure-group">
<legend><H5>Vous êtes</H5></legend>
<input id="radio-group--madame" type="radio" name="radio-group" value="madame"> <label for="radio-group--madame">Madame</label>
<input id="radio-group--monsieur" type="radio" name="radio-group" value="monsieur"> <label for="radio-group--monsieur">Monsieur</label>
</fieldset>
<div class="form-elements">
<fieldset class="pure-group">
<label for="firstname">Votre prénom</label>
<input id="firstname" name="Prénom" placeholder="indiquez votre prénom" />
</fieldset>
<div class="form-elements">
<fieldset class="pure-group">
<label for="name">Votre nom</label>
<input id="name" name="Nom" placeholder="indiquez votre nom" />
</fieldset>
<fieldset class="pure-group">
<label for="email"><em>Votre</em> Adresse email</label>
<input id="email" name="Votre adresse email" type="email" value=""
required placeholder="Alice#paydesmerv.... ou votre vrai adresse pour recevoir la confirmation"/>
</fieldset>
<fieldset class="pure-group">
<legend><H5>Votre dépense</H5></legend>
<label for="date">Date</label>
<input id="date" type="date" name="date de la dépense" value="">
</fieldset>
<fieldset class="pure-group">
<label for="time">Heure de la dépense</label>
<input id="time" type="time" name="Heure de la dépense" value="">
</fieldset>
<fieldset class="pure-group">
<label for="menu">Type de dépense</label>
<select id="menu" name="Type de dépense">
<option selected="">Je ne sais pas quel type de dépense choisir</option>
<option>Carburant (essence, diesel, gasoil)</option>
<option>Location de matériel (voiture, informatique, photocopieur)</option>
<option>Voyages et déplacements (train, transports, taxi, VTC, péages, parking, avion)</option>
<option>Frais postaux (La Poste, timbres, colis, lettre recommandée)</option>
<option>Frais de mission (repas, restaurants)</option>
<option>Frais de missions (logement, hôtel)</option>
<option>Divers</option>
</select>
</fieldset>
<fieldset class="pure-group">
<label for="number">Montant de la dépense en €</label>
<input id="number" type="number" name="Montant de la dépense" min="0" step="0.01" value="0.00">
</fieldset>
<fieldset class="pure-group">
<label for="message">Message: </label>
<textarea id="message" name="Message Facultatif" rows="10"
placeholder="Vous pouvez apporter des précisions sur la dépense ici..."></textarea>
</fieldset>
<fieldset class="pure-group honeypot-field">
<label for="honeypot">To help avoid spam, utilize a Honeypot technique with a hidden text field; must be empty to submit the form! Otherwise, we assume the user is a spam bot.</label>
<input id="honeypot" type="text" name="honeypot" value="" />
</fieldset>
<legend><H5>Ajoutez le justificatif</H5></legend>
<p> Pas de remboursement possible sans justificatif</p>
<!-- Here is the issue: code below sends the file to my drive but no new row is added to the spreadsheet. -->
<div class="row">
<div class="file-field input-field col s12">
<div class="btn">
<span>Fichier</span>
<input id="files" type="file" name="Fichier reçu" multiple>
</div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="choisissez un fichier sur votre ordinateur">
</div>
</div>
</div>
<!-- code below creates new row with filename but does not upload the file to drive...
exemple from : https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_input_type_file -->
<form action="/action_page.php">
Select files: <input type="file" name="Fichier reçu"><br><br>
<input type="submit">
</form>
<button class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
</div>
<!-- Customise the Thankyou Message People See when they submit the form: -->
<div class="thankyou_message" style="display:none;">
<h2><em>Thanks</em> for contacting us!
We will get back to you soon!</h2>
</div>
</form>
<!-- Submit the Form to Google Using "AJAX" -->
<script data-cfasync="false" src="form-submission-handler.js"></script>
<!-- END -->
<div class="row">
<div class="input-field col s12" id = "progress">
</div>
</div>
<div id="success" style="display:none">
<h5 class="left-align teal-text">File Uploaded</h5>
<p>Your file has been successfully uploaded.</p>
<p>The pro version (see demo form) includes a visual drag-n-drop form builder, CAPTCHAs, the form responses are saved in a Google Spreadsheet and respondents can upload multiple files of any size.</p>
<p class="center-align"><a class="btn btn-large" href="https://gum.co/GA14?wanted=true" target="_blank">Upgrade to Pro</a></p>
</div>
</form>
<div class="fixed-action-btn horizontal" style="bottom: 45px; right: 24px;">
<a class="btn-floating btn-large red">
<i class="large material-icons">menu</i>
</a>
<ul>
<li><a class="btn-floating red" href="shorturl" target="_blank" title="Buy License - File Upload Form"><i class="material-icons">monetization_on</i></a></li>
<li><a class="btn-floating blue" href="shorturl" target="_blank" title="Video Tutorial"><i class="material-icons">video_library</i></a></li>
<li><a class="btn-floating green" href="http://www.labnol.org/internet/file-upload-google-forms/29170/" target="_blank" title="How to Create File Upload Forms"><i class="material-icons">help</i></a></li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"></script>
<script src="https://gumroad.com/js/gumroad.js"></script>
<script>
var file,
reader = new FileReader();
reader.onloadend = function(e) {
if (e.target.error != null) {
showError("File " + file.name + " could not be read.");
return;
} else {
google.script.run
.withSuccessHandler(showSuccess)
.uploadFileToGoogleDrive(e.target.result, file.name, $('input#nom').val(), $('input#prenom').val());
}
};
function showSuccess(e) {
if (e === "OK") {
$('#forminner').hide();
$('#success').show();
} else {
showError(e);
}
}
function submitForm() {
var files = $('#files')[0].files;
if (files.length === 0) {
showError("Choisissez un fichier a télécharger");
return;
}
file = files[0];
if (file.size > 1024 * 1024 * 5) {
showError("The file size should be < 5 MB. Please <a href='http://www.labnol.org/internet/file-upload-google-forms/29170/' target='_blank'>upgrade to premium</a> for receiving larger files in Google Drive");
return;
}
showMessage("Téléchargement du fichier");
reader.readAsDataURL(file);
}
function showError(e) {
$('#progress').addClass('red-text').html(e);
}
function showMessage(e) {
$('#progress').removeClass('red-text').html(e);
}
</script>
So, I'd like to have a unique form to send emails, log into sheets and save file in drive.
Additionally, that would be perfect is the file link could appear inside sheets and if the uploaded file could also be sent as attachment with the email.
Thanks a lot for proof reading my codes and putting me on the right direction!
Collecting Receipt Information
This function collects Date,Vendor,Amount and Uploads an image. It runs as both a dialog and/or a webapp. The spreadsheet displays the images url which allows you to hover over in order to get a link to the image which can be view in a default viewer.
This is the form:
Here's the code:
Code.gs:
function onOpen() {
SpreadsheetApp.getUi().createMenu('Receipt Collection')
.addItem('Get Receipt', 'showAsDialog')
.addToUi();
}
function uploadTheForm(theForm) {
Logger.log(JSON.stringify(theForm));
var rObj={};
rObj['vendor']=theForm.vendor;
rObj['amount']=theForm.amount;
rObj['date']=theForm.date;
rObj['notes']=theForm.notes;
var fileBlob=Utilities.newBlob(theForm.bytes, theForm.mimeType, theForm.filename);
var fldr = DriveApp.getFolderById(receiptImageFolderId);
rObj['file']=fldr.createFile(fileBlob);
rObj['filetype']=fileBlob.getContentType();
Logger.log(JSON.stringify(rObj));
var cObj=formatFileName(rObj);
Logger.log(JSON.stringify(cObj));
var ss=SpreadsheetApp.openById(SSID);
ss.getSheetByName('Receipt Information').appendRow([cObj.date,cObj.vendor,cObj.amount,cObj.notes,cObj.file.getUrl()]);
var html=Utilities.formatString('<br />FileName: %s',cObj.file.getName());
return html;
}
function formatFileName(rObj) {
if(rObj) {
Logger.log(JSON.stringify(rObj));
var mA=rObj.date.split('-');
var name=Utilities.formatString('%s_%s_%s.%s',Utilities.formatDate(new Date(mA[0],mA[1]-1,mA[2]),Session.getScriptTimeZone(),"yyyyMMdd"),rObj.vendor,rObj.amount,rObj.filetype.split('/')[1]);
rObj.file.setName(name);
}else{
throw('Invalid or No File in formatFileName() upload.gs');
}
return rObj;
}
function doGet() {
var output=HtmlService.createHtmlOutputFromFile('receipts').setTitle('Receipt Information');
return output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL).addMetaTag('viewport', 'width=360, initial-scale=1');
}
function showAsDialog() {
var ui=HtmlService.createHtmlOutputFromFile('receipts');
SpreadsheetApp.getUi().showModelessDialog(ui, 'Receipts')
}
receipts.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function(){
google.script.run
.withSuccessHandler(function(rObj){
$('#dt').val(rObj.date);
//$('#vndr').val(rObj.vendor);
//$('#amt').val(rObj.amount);
//$('#notes').val(rObj.notes);
})
.initForm();
});
function fileUploadJs(frmData) {
var amt=$('#amt').val();
var vndr=$('#vndr').val();
var img=$('#img').val();
if(!amt){
window.alert('No amount provided');
$('#amt').focus();
return;
}
if(!vndr) {
window.alert('No vendor provided');
$('#vndr').focus();
return;
}
if(!img) {
window.alert('No image chosen');
$('#img').focus();
}
document.getElementById('status').style.display ='inline';
const file = frmData.receipt.files[0];
const fr = new FileReader();
fr.onload = function(e) {
const obj = {vendor:frmData.elements.vendor.value, date:frmData.elements.date.value, amount: frmData.elements.amount.value, notes: frmData.elements.notes.value, filename: file.name, mimeType:file.type, bytes:[...new Int8Array(e.target.result)]};
google.script.run
.withSuccessHandler(function(hl){
document.getElementById('status').innerHTML=hl;
})
.uploadTheForm(obj);
};
fr.readAsArrayBuffer(file);
}
console.log('My Code');
</script>
<style>
input,textarea{margin:5px 5px 5px 0;}
</style>
</head>
<body>
<h3 id="main-heading">Receipt Information</h3>
<div id="formDiv">
<form id="myForm">
<br /><input type="date" name="date" id="dt"/>
<br /><input type="number" name="amount" placeholder="Amount" id="amt" />
<br /><input type="text" name="vendor" placeholder="Vendor" id="vndr"/>
<br /><textarea name="notes" cols="40" rows="2" placeholder="NOTES" id="notes"></textarea>
<br/>Receipt Image
<br /><input type="file" name="receipt" id="img" />
<br /><input type="button" value="Submit" onclick="fileUploadJs(this.parentNode)" />
</form>
</div>
<div id="status" style="display: none">
<!-- div will be filled with innerHTML after form submission. -->
Uploading. Please wait...
</div>
</body>
</html>
global.gs
var receiptImageFolderId='your receipt image folder id';
var SSID='your spreadsheet id';
The Spreadsheet Looks Like this:
Note I changed image Id to image Url so that you can just click on the url to get a viewer to look at the image. I think this is much cleaner than trying to put images of varying sizes into the spreadsheet.