2

This is my first approach with js and html coding, please be as much simple as possible!

I want to improve the form developed in my web App making possible to upload image. My goal is to:

  • Add input type file on my web App
  • Send the file to server side
  • Save the file in the G Drive, take the link and save it in Google Sheet

To do this I have already added in my html a file input area, but I'm not sure about how I may manage it in script section.

All the information added in the form are send to server in an object called measureInfo and I want to maintain this routine. When I try to add

measureInfo.media = document.getElementById('fileUpload').files

it doesn't run and console return `Failed due to illegal value in property: media.

Here I report some string of code that may help to answer. If you have some suggests about how manage file in server side with DriveApp please share!

   <script>
            measureInfo.media= document.getElementById('fileUpload').files

            google.script.run.sendToDatabase(measureInfo);
</script>
<form action="#">
    <!-- Upload File -->
    <div class="file-field input-field">
        <div class="btn-large blue darken-3">
            <span>Media</span>
            <input type="file" id= 'fileUpload' name ='fileUpload'>
        </div>
        <div class="file-path-wrapper">
            <input class="file-path validate" type="text" placeholder = 'Upload Media'>
        </div>
    </div>
</form>
  • 1
    Welcome to [so] Please add a brief description of your search /research efforts as is suggested in [ask]. Tip Start by searching about Google Drive Picker. – Rubén Jun 16 '20 at 14:30
  • You know that a basic google form can handle uploading files now, what else does your webapp do? – J. G. Jun 16 '20 at 16:26
  • What event is supposed to trigger this? Form submission? – Iamblichus Jun 17 '20 at 10:49

3 Answers3

1

You could use FileReader.onload event to build an object that can be passed server-side:

const file = document.getElementById('fileUpload').files[0];
const fr = new FileReader();
fr.onload = (e) => {
  const data = e.target.result.split(",");
  measureInfo.media = {fileName: file.name, mimeType: file.type, data: data[1]};       
  google.script.run.sendToDatabase(measureInfo);
}
fr.readAsDataURL(file);

Reference:

Iamblichus
  • 18,540
  • 2
  • 11
  • 27
0

Here's some code I use for saving receipts:

HTML with JS:

<!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);
        })
        .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';
        google.script.run
        .withSuccessHandler(function(hl){
          document.getElementById('status').innerHTML=hl;
        })
        .uploadTheForm(frmData)
      }
      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"></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>

GS:

function uploadTheForm(theForm) {
  var rObj={};
  rObj['vendor']=theForm.vendor;
  rObj['amount']=theForm.amount;
  rObj['date']=theForm.date;
  rObj['notes']=theForm.notes
  var fileBlob=theForm.receipt;
  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 initForm() {
  var datestring=Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "yyyy-MM-dd");
  return {date:datestring};
}
Cooper
  • 59,616
  • 6
  • 23
  • 54
  • You passed the image, together with all other input, to GS using "this.parentNode" . If I want to pass the image through document.getElementById('img'), how can I adapt the script so that it doesn't return error? – Renato Toni Jun 17 '20 at 09:35
  • I have no idea what you’re trying to do. You can’t getElementById() unless it’s in the DOM. – Cooper Jun 17 '20 at 11:17
  • My goal is to pass the image from html to GS as a proprety of the object named measureInfo that I use as argument of the function sendToDatabase(x). In the script I have defined measureInfo.media=document.getElementById('fileUpload').files Console.log(measureInfo.media) works correctly and it shows me the file list but, when the function "google.script.run.sendToDatabase(measureInfo)" runs it return an error due to an "illegal value in the property: media". I want to know if it's possible to fix this error and pass the file as a proprety of measureInfo object. – Renato Toni Jun 17 '20 at 15:28
0
<script>
   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);
   
   function handleFormSubmit(formObject){
   google.script.run.processForm(formObject);
   document.getElementById("myForm").reset();
   }
   
</script>
<script>
   function uploadTheForm(theForm) {
   var rObj={};
   rObj['vendor']=theForm.vendor;
   rObj['amount']=theForm.amount;
   rObj['date']=theForm.date;
   rObj['notes']=theForm.notes
   var fileBlob=theForm.receipt;
   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 initForm() {
   var datestring=Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "yyyy-MM-dd");
   return {date:datestring};
   }
</script>
<!DOCTYPE html>
<html lang="en">
   <head>
      <base target="_top">
      <?!= include('JavaScript'); ?>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
      <head>
         <script>
            $(function(){
              google.script.run
              .withSuccessHandler(function(rObj){
                $('#dt').val(rObj.date);
              })
              .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';
              google.script.run
              .withSuccessHandler(function(hl){
                document.getElementById('status').innerHTML=hl;
              })
              .uploadTheForm(frmData)
            }
            console.log('My Code');
            
         </script>
         </head
   <body>
      <div class="form-row">
      <div class="form-group col-md-12">
      <h5 style="text-align:center;">Upload Photo</h5>
      <div class="form-row">
      <div class="form-group col-md-4" style="word-wrap: break-word">
         <p3 style="text-align:left; color:red">
         Notice! Please doff eyewear & mask and avoid sunlight exposure when taking selfie!</p>
      </div>
      <div class="form-group col-md-6"><img id="output" width="200" height="200" src="https://www.citypng.com/public/uploads/small/116395943260tji5ordfujy44njydzhlidv8reqpmtun7ggx1oszpz1dcistzxnmag7do6vxkjxphlsgueuurkg9pkpbwgorvv9lratpxm38rp5.png"  alt="photo" style="border:gray; border-width:2px; border-style:solid;"/></div>
      <div class="form-group col-md-12">
         <center>
         &nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp;<input class="file-path validate" type="file" id="fileUpload" name="fileUpload" value='fileUpload'  accept="image/*" onchange="loadFile(event)">
         <script>
            var loadFile = function(event) {
              var output = document.getElementById('output');
              output.src = URL.createObjectURL(event.target.files[0]);
              output.onload = function() {
                URL.revokeObjectURL(output.src) // free memory
              }
            };
         </script>
      </div>
   </body>
</html>


  [1]: https://i.stack.imgur.com/98vPf.png
Jayson
  • 1
  • I'm not getting the exact image link when i save file upload and data entry were not saving too if i include file. – Jayson Mar 04 '22 at 09:19
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 04 '22 at 10:24