David Paiva
David Paiva

Reputation: 3

send a file from a <input> to google drive, but not directly (I need to do some data treatment first using GAS)

I have a huge form with all kind of inputs that I need to do data treatment and then register directly on multiples spreadsheets. The first part of getting the values and sending it to the spreadsheets I am able to do with the exception of two inputs that are file inputs.

Then I found this:

https://gist.github.com/tanaikech/280b782ee0518aa083a4fe0d71384823

The concept works fine if I use as it is, in other words, if I get the value of an input and call saveFile(e) to just save the file on the google drive it will work.

But I don't need this, I need that instead of:

google.script.run.withSuccessHandler(e => console.log(e)).saveFile(obj);

I have something like:

return obj;

I am trying to work with async functions but my knowledge on that area is really sparse and I am having a hard time in understand how it's work. It's even harder when we relate it with fileReader. this is my actual code:

 async function saveFileJS(f) {

      console.log("arquivo: " + f);

      const file = f.files[0];
      const fr = new FileReader();
      var retorno = ""; //variavél para receber o retorno do obj

      fr.onload = await function(e) {
        const obj = {
          filename: file.name,
          mimeType: file.type,
          bytes: [...new Int8Array(e.target.result)]
        };
        console.log("file: " + obj);
        console.log("nome do arquivo: " + obj.filename);
        //google.script.run.withSuccessHandler(e => console.log(e)).saveFile(obj,destino);
        
        retorno = obj; // determina o retorno como o obj
        
      };

      fr.readAsArrayBuffer(file);

      console.log("objeto = " + retorno);

      return retorno; //retorna obj 


  }

But it's not working as I expect. when I call this function in another js function, even if I make the caller function async and even if I do

file = await saveFileJS(f);

looking at the log, it's returns the: console.log("arquivo: " + f); and console.log("objeto = " + retorno); before the:

        console.log("file: " + obj);
        console.log("nome do arquivo: " + obj.filename);

that's means that everything in between fr.onload it's async even with the await there and just works because google.script.run.withSuccessHandler will wait everything before it.

putting the return inside the function(e) not works either, since will just return the obj value to fr.onload

about the whole code flow...

first it's calls the preparaVetores()

https://pastebin.com/z4gPf76U

This code get the values from several fields and organize it on arrays, then send it to the server side using google.script.run.finalizarFormulario But before that, it's do a data treatment to the both files received from the inputs, to achieve that it's use the following code (I use await before the function call):

https://pastebin.com/mxJiJJ3e

To be honest, I did not create this code so I can't really explain how it's works but I can explain what I tried to change.

First. I commented /google.script.run.withSuccessHandler(e => console.log(e)).saveFile(obj,destino); because I don't want it to send to the server side yet, instead I added the line: retorno = obj; // determina o retorno como o obj and in the end of the function: return retorno; //retorna obj I did that on the hope that it would return the object in the previous function (foto = await saveFileJS(foto); ) but it's didn't work (I will explain what is the return later)

After doing that it should use script.run and do all the data treatment before sending it to the spreadsheets:

https://pastebin.com/gi6qjGeQ

Most of this code just do data treatment that it's seems to doing it's job, the issue is here:

  Logger.log("gravando a foto " + foto);
  foto = saveFile(foto, pastaFotos);
  Logger.log(foto);
  Logger.log("gravando o currículo " + curriculo);
  curriculo = saveFile(curriculo, pastaCurriculos);
  Logger.log(curriculo);

saveFile return this error:

TypeError: Cannot read properties of undefined (reading 'bytes')
    at saveFile(MAIN/main:1004:34)
    at finalizarFormulario(MAIN/main:790:10)

and saveFile is:

https://pastebin.com/jrmFmTgU

Again, I didn't create this code, but I can explain what i changed here.

  file.moveTo(DriveApp.getFolderById(destino));
 
  let fileURL = file.getUrl();
 
  Logger.log(fileURL);
 
  return fileURL;

The added code move the file from the root to a specific code (destino), get the url of the file after moving the folder and return the url. Because what's matters to me is the file url and not the blob itself.

in the client side, the console.log() from the saveFileJS runs in this order:

line 3, line 25 (...) line 15, line 16 the (...) represents console.log() generate in the caller function preparaVetores().

It's means saveFileJS is async, that I know. I just don't know what I have to change in saveFileJS() to make it work as should be. I tried to change fr.onload = function(e) { to fr.onload = await function(e) { but it didn't nothing.

Thank you.

Upvotes: 0

Views: 85

Answers (1)

James
James

Reputation: 22247

Maybe there's a way to do it with async/await but this type of thing can be easier to do using Promises.

function saveFileJS(f) {
   return new Promise((resolve, reject) => {
      console.log("arquivo: " + f);
      const file = f.files[0];
      const fr = new FileReader();

      fr.onload = function(e) {
        const obj = {
          filename: file.name,
          mimeType: file.type,
          bytes: [...new Int8Array(e.target.result)]
        };
        console.log("file: " + obj);
        console.log("nome do arquivo: " + obj.filename);
        //google.script.run.withSuccessHandler(e => console.log(e)).saveFile(obj,destino);
        resolve(obj); // 
      };

      fr.readAsArrayBuffer(file);
   });
  }
  
  async function testIt() {
    const file = await saveFileJS(someFile);
    console.log(file.mimeType);
  }

Upvotes: 0

Related Questions