简体   繁体   English

获取function外的变量值创建文件

[英]Get the value of the variable outside the function to create a file

I would like to know how I can return the name of the folder created in the folder variable outside the createOrGetFolder function, the intention is to be able to create a file with the same name as the folder created, in this code here:我想知道如何返回在createOrGetFolder function 之外的folder变量中创建的文件夹的名称,目的是能够创建一个与创建的文件夹同名的文件,在此代码中:

const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile(folder, data);

This is my complete code from the .gs file:这是.gs文件中的完整代码:

/**
* Modified script written by Tanaike and CharlesPlucker
*
* Additional Script by Tyrone
* version 20.01.2023.1
*/

        function doGet(e) {
          return HtmlService.createTemplateFromFile('forms0101.html').evaluate();
        }
        
        
        function getOAuthToken() {
          return ScriptApp.getOAuthToken();
        }
        
        
        function getParent(){
          var ss = SpreadsheetApp.getActiveSpreadsheet();
          var id = ss.getId();
          var parent = DriveApp.getFileById(id).getParents().next().getId();
          return parent
        }
        
        function getLimitFolder(){
          var ss = SpreadsheetApp.getActiveSpreadsheet();
          var pastapai = DriveApp.getFileById(ss.getId()).getParents();
          var limitfolder = pastapai.next().getFoldersByName("_").next().getId();
          return limitfolder
        }
        
        /**
        * creates a folder under a parent folder, and returns it's id. If the folder already exists
        * then it is not created and it simply returns the id of the existing one
        */
        
        function createOrGetFolder(folderName, parentFolderId) {
          try {
            var parentFolder = DriveApp.getFolderById(parentFolderId), folder;
            if (parentFolder) {
              var foldersIter = parentFolder.getFoldersByName("Video");
              if (foldersIter.hasNext()) {
                var videoFolder = foldersIter.next();
                var nextFolderName = folderName + "-01";
                while (!folder) {
                  video_folder = videoFolder.getFoldersByName(nextFolderName);
                  if (video_folder.hasNext()) {
                    folder = video_folder.next();
                    var files = folder.getFiles();
                    if (files.hasNext()) {
                      var [a, b] = nextFolderName.split("-");
                      nextFolderName = `${a}-${String(Number(b) + 1).padStart(2, "0")}`;
                      folder = null;
                    }
                  } else {
                    folder = videoFolder.createFolder(nextFolderName);
                  }
                }
              } else {
                folder = parentFolder.createFolder("Video");
                folder = folder.createFolder(folderName);
              }
            } else {
              throw new Error("Parent Folder with id: " + parentFolderId + " not found");
            }
            return folder.getId();
          } catch (error) {
            return error;
          }
        }
        
        const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile("Sample.csv", data);
    
    
    // NOTE: always make sure we use DriveApp, even if it's in a comment, for google to import those
    // libraries and allow the rest of the app to work. see https://github.com/tanaikech/Resumable_Upload_For_WebApps

Note that in const saveDataAsCSV the currently file creation name is Sample.csv , and this is where I want to apply the folder variable that is in the function createOrGetFolder(folderName, parentFolderId)请注意,在const saveDataAsCSV中,当前文件创建名称为Sample.csv ,这是我要应用 function createOrGetFolder(folderName, parentFolderId)中的folder变量的地方

And this is the complete code of the HTML file:这是HTML文件的完整代码:

/**
* Modified script written by Tanaike and CharlesPlucker
*
* Additional Script by Tyrone
* version 20.01.2023.1
*/

<!DOCTYPE html>
<html>
  <head>
    <base target="_blank">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Drive Multi Large File Upload</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">
     
     <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <style>
      @import url('https://fonts.googleapis.com/css2?family=Rubik:wght@400;600;700&display=swap');
      
      .disclaimer{
        width: 480px; 
        color: #646464;
        margin: 20px auto;
        padding:0 16px;
        text-align:center;
        font:400 12px Rubik,sans-serif;
        }

      h5.center-align.teal-text {
        font:700 26px Rubik,sans-serif;
        color: #00F498!important;
      }

      .row {
        font:600 14px Rubik,sans-serif;
      }

      .btn {
        background-color: black;
      }

      .btn:hover {
        background-color: #00F498;
      }

      body {
        margin-top: -40px;
      }

      #progress {
        color: #00000;
      }
      
      .disclaimer a{
        color: #00BCAA;
        }

      #credit{
        display:none
        }
    </style>
  </head>
  <body>
    <form class="main" id="form" novalidate="novalidate" style="max-width: 480px;margin: 40px auto;">
 <div id="forminner">
  <h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">YOUR NAME</h5>
    <div class="row">
          <div class="input-field col s12">
            <input id="name01" type="text" name="Name" class="validate" required="required" aria-required="true">
            <label for="name" class="">Name</label>
          </div>
        </div>
    
      <h5 class="center-align teal-text" style="margin-bottom: -10px; font-size: 20px; font-family: Rubik; ">SOME DESCRIPTION</h5>
        <div class="row">
          <div class="input-field col s12">
            <input id="description" type="text" name="Description" class="validate" required="required" aria-required="true">
            <label for="name">Description</label>
          </div>
        </div>

    <div class="row">
      <div class="col-8 col-md-4">
        <h6>Model</h6>       
        <select class="custom-select" id="Model">
          <option selected="">Choose...</option>
          <option value="01">01</option>
          <option value="02">02</option>
          <option value="03">03</option>
        </select> 
          &nbsp;

        <h6>Color</h6>        
        <select class="custom-select" id="Color">
          <option selected="">Choose...</option>
          <option value="Red">Red</option>
          <option value="Green">Green</option>
        </select>   
      </div>
  </div>

    
        <div class="row">
          <div class="col s12">
            <h5 class="center-align teal-text">Upload the Video File</h5>
           
          </div>
        </div>
        
        <div class="row">
          <div class="file-field input-field col s12">
            <div id="input-btn" class="btn">
              <span>File</span>
              <input id="files" type="file" single="">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path validate" type="text" placeholder="Select the file">
            </div>
          </div>
        </div>

        <div class="row">
          <div class="input-field col s6">
            <button id="submit-btn" class="waves-effect waves-light btn submit-btn" type="submit" onclick="submitForm(); return false;">Submit</button>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12 hide" id="update">
            <hr>
            <p>
              Por favor, aguarde enquanto seu arquivo está sendo carregado.<br><span style="color: #00000;"><b>Não feche ou atualize a janela durante o upload.</b></span>
            </p>
          </div>
        </div>
        <div class="row">
          <div class="input-field col s12" id="progress">
          </div>
        </div>
      </div>
     </div> 
      <div id="success" style="display:none">
        <h5 class="center-align teal-text">Tudo certo!</h5>
        <p>Se você já preencheu todos os campos é só fechar essa janela e clicar em enviar!</p>
        <button id="fechar" class="waves-effect waves-light btn submit-btn" style ="transform: translateX(160%);" type="button" onclick="google.script.host.close()">Fechar</button>
      </div>
    </form>

    <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 upload_folder = "01";
      const chunkSize = 5242880;
      const uploadParentFolderId = <?=getParent()?>; // creates a folder inside of this folder
      const limitfolder = <?=getLimitFolder()?>;

      function closer(){
        google.script.host.close();
      }

      function submitForm() {

        // Added the below script.
        if ($('#submit-btn.disabled')[0]) return; // short circuit

        var name = upload_folder
        var files = [...$('#files')[0].files]; // convert from FileList to array

        
        if (files.length === 0) {
          showError("Por favor, selecione um arquivo");
          return;
        }

        var name = $('#name01').val();
        var description = $('#description').val();
        var model = $('#Model').val();
        upload_folder = model;
        var color = $('#Color').val();
        var form_values = [name, description, model, color];
        form_values = form_values.map(r => r.replaceAll(",", "#")); // Essa linha substitui todas as "," por "#" antes de gerar o .csv
        var data = form_values.join(",");
        google.script.run.saveDataAsCSV(data, uploadParentFolderId);
        google.script.run.saveDataAsCSV(data, limitfolder);

        disableForm(); // prevent re submission

        // the map and reduce are here to ensure that only one file is uploaded at a time. This allows
        // the promises to be run sequentially
        files.map(file => uploadFilePromiseFactory(file))
            .reduce((promiseChain, currentTask) => {
              return promiseChain.then(currentTask);
            }, Promise.resolve([])).then( () => {
              console.log("Completed all files upload");
              showSuccess();
            });
      }

      function disableForm() {
        $('#submit-btn').addClass('disabled');
        $('#input-btn').addClass('disabled');
        $('#update').removeClass('hide');
         $('#update').removeClass('hide');
      }

      function uploadFilePromiseFactory(file) {
        return () => {
          console.log("Processing: ", file.name);
          return new Promise((resolve, reject) => {

            showProgressMessage("Seu arquivo está sendo carregado");

            var fr = new FileReader();
            fr.fileName = file.name;
            fr.fileSize = file.size;
            fr.fileType = file.type;
            // not sure of a better way of passing the promise functions down
            fr.resolve = () => resolve();
            fr.reject = (error) => reject(error);
            fr.onload = onFileReaderLoad;
            fr.readAsArrayBuffer(file);
          });
        };
      }
      
      /**
       * Gets called once the browser has loaded a file. The main logic that creates a folder
       * and initiates the file upload resides here
       */
      function onFileReaderLoad(onLoadEvent) {
        var fr = this;

        var newFolderName = upload_folder
        createOrGetFolder(newFolderName, uploadParentFolderId).then(newFolderId => {
          console.log("Found or created guest folder with id: ", newFolderId);
          uploadFileToDriveFolder.call(fr, newFolderId).then(() => {
              fr.resolve();
            }, (error) => {
              fr.reject(error);
            });
          },
          (error) => {
            if (error) {
              showError(error.toString());
            }
            console.log("onFileReaderLoad Error2: ", error);
          });

      }

      /**
       * call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
       * createFolder and findFolderById
       */
      function createOrGetFolder(folderName, parentFolderId) {
        return new Promise((resolve, reject) => {
          google.script.run.withSuccessHandler(response => {
            console.log("createOrGetFolder response: ", response);
            if (response && response.length) {
              resolve(response);
            }
            reject(response);
          }).createOrGetFolder(folderName, parentFolderId);
        });
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function uploadFileToDriveFolder(parentFolderId) {
        var fr = this;
        return new Promise((resolve, reject) => {
          var fileName = fr.fileName;
          var fileSize = fr.fileSize;
          var fileType = fr.fileType;
          console.log({fileName: fileName, fileSize: fileSize, fileType: fileType});
          var buf = fr.result;
          var chunkpot = getChunkpot(chunkSize, fileSize);
          var uint8Array = new Uint8Array(buf);
          var chunks = chunkpot.chunks.map(function(e) {
            return {
               data: uint8Array.slice(e.startByte, e.endByte + 1),
               length: e.numByte,
               range: "bytes " + e.startByte + "-" + e.endByte + "/" + chunkpot.total,
            };
          });
          google.script.run.withSuccessHandler(oAuthToken => {
            var xhr = new XMLHttpRequest();
            xhr.open("POST", "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable");
            xhr.setRequestHeader('Authorization', "Bearer " + oAuthToken);
            xhr.setRequestHeader('Content-Type', "application/json");
            xhr.send(JSON.stringify({
              mimeType: fileType,
              name: fileName,
              parents: [parentFolderId]
            }));
            xhr.onload = () => {
              doUpload(fileName, {
                location: xhr.getResponseHeader("location"),
                chunks: chunks,
              }).then(success => {
                resolve(success);
                console.log("Successfully uploaded: ", fileName);
              },
              error => {
                reject(error);
              });
            };

            xhr.onerror = () => {
              console.log("ERROR: ", xhr.response);
              reject(xhr.response);
            };
          }).getOAuthToken();
        });
      }

      function showSuccess() {
        $('#forminner').hide();
        $('#success').show();
        $('#fechar').show();
      }

      function showError(e) {
        $('#progress').addClass('red-text').html(e);
      }

      function showMessage(e) {
        $('#update').html(e);
      }

      function showProgressMessage(e) {
        $('#progress').removeClass('red-text').html(e);
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function doUpload(fileName, e) {
        return new Promise((resolve, reject) => {
          showProgressMessage("Carregando: <span style='color: #00F498 ;'>" + "0%</span>");
          var chunks = e.chunks;
          var location = e.location;
          var cnt = 0;
          var end = chunks.length;
          var temp = function callback(cnt) {
            var e = chunks[cnt];
            var xhr = new XMLHttpRequest();
            xhr.open("PUT", location, true);
            console.log("content range: ", e.range);
            xhr.setRequestHeader('Content-Range', e.range);
            xhr.send(e.data);
            xhr.onloadend = function() {
                var status = xhr.status;
                cnt += 1;
                console.log("Uploading: " + status + " (" + cnt + " / " + end + ")");
                showProgressMessage("Carregando: <span style='color: #00F498 ;'>" 
                       + Math.floor(100 * cnt / end) + "%</span>" );
                if (status == 308) {
                    callback(cnt);
                } else if (status == 200) {
                    $("#progress").text("Done.");
                    resolve();
                } else {
                    $("#progress").text("Error: " + xhr.response);
                    reject();
                }
            };
          }(cnt);
        });
      }

      /**
      * Helper functions modified from:
      * https://github.com/tanaikech/Resumable_Upload_For_WebApps
      */
      function getChunkpot(chunkSize, fileSize) {
        var chunkPot = {};
        chunkPot.total = fileSize;
        chunkPot.chunks = [];
        if (fileSize > chunkSize) {
            var numE = chunkSize;
            var endS = function(f, n) {
                var c = f % n;
                if (c == 0) {
                    return 0;
                } else {
                    return c;
                }
            }(fileSize, numE);
            var repeat = Math.floor(fileSize / numE);
            for (var i = 0; i <= repeat; i++) {
                var startAddress = i * numE;
                var c = {};
                c.startByte = startAddress;
                if (i < repeat) {
                    c.endByte = startAddress + numE - 1;
                    c.numByte = numE;
                    chunkPot.chunks.push(c);
                } else if (i == repeat && endS > 0) {
                    c.endByte = startAddress + endS - 1;
                    c.numByte = endS;
                    chunkPot.chunks.push(c);
                }
            }
        } else {
            var chunk = {
                startByte: 0,
                endByte: fileSize - 1,
                numByte: fileSize,
            };
            chunkPot.chunks.push(chunk);
        }
        return chunkPot;
      }

    </script>

  </body>

</html>

As folder is without the var prefix, I figured it should work, as in theory this makes it a global variable... however I still get the folder is undefined message in the console.由于folder没有var前缀,我认为它应该可以工作,因为理论上这使它成为一个全局变量......但是我仍然在控制台中收到folder is undefined的消息。

I also tried calling the function before the file creation code, like this:我还尝试在文件创建代码之前调用 function,如下所示:

createOrGetFolder(folderName, parentFolderId);
const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile(folder, data);

But that way I get the message folderName is undefined.但是这样我得到消息folderName is undefined.


Based on the suggestion made in the The WizEd answer's comments , this was my last attempt:根据The WizEd answer's comments中的建议,这是我最后一次尝试:

Modified excerpt in the .gs file: .gs文件中的修改摘录:

const saveDataAsCSV = (data, folderId) => DriveApp.getFolderById(folderId).createFile(newFolderId, data);

Modified excerpt in the HTML file: HTML文件中的修改摘录:

       var newFolderId = "";
      /**
       * call to the DriveApp api. Wrapped in a promise in case I want to address timing issues between a
       * createFolder and findFolderById
       */
      function createOrGetFolder(folderName, parentFolderId) {
        return new Promise((resolve, reject) => {
          google.script.run.withSuccessHandler(response => {
            console.log("createOrGetFolder response: ", response);
            if (response && response.length) {
              resolve(response);
            }
            reject(response);
          }).createOrGetFolder(folderName, parentFolderId);
          newFolderId = createOrGetFolder(folderName, parentFolderId);
        });
      }

That way I still can't get the name of the folder created or used...这样我仍然无法获得创建或使用的文件夹的名称......

Where am I going wrong?我哪里错了?

Global variable are not persistent.全局变量不是持久的。 What that means is when a function is executed the instance creates the global variable but releases it when the function or function chain finishes.这意味着当执行 function 时,实例会创建全局变量,但会在 function 或 function 链完成时释放它。

Here func1() calls func2() so the instance of the global variable is perserved.这里func1()调用func2()所以全局变量的实例被保留。

However if I run func2() by itself following running func1() it is reset to blank但是,如果我在运行 func1( func2()之后自行运行func1() ,它将重置为空白

Run func1()运行 func1()

var globalVariable = "";

function func1 () {
  try {
    console.log("globalVariable in func1 = ["+globalVariable+"]")
    globalVariable = "Hello";
    func2();
    console.log("globalVariable from func2 = ["+globalVariable+"]")
  }
  catch(err) {
    console.log("Error in func1: "+err);
  }
}

function func2 () {
  try {
    console.log("globalVariable in func2 = ["+globalVariable+"]")
    globalVariable = "Good bye";
  }
  catch(err) {
    console.log("Error in func2: "+err);
  }
}

11:53:15 AM Notice  Execution started
11:53:17 AM Info    globalVariable in func1 = []
11:53:17 AM Info    globalVariable in func2 = [Hello]
11:53:17 AM Info    globalVariable from func2 = [Good bye]
11:53:16 AM Notice  Execution completed

Now run func2()现在运行 func2()

11:57:38 AM Notice  Execution started
11:57:39 AM Info    globalVariable in func2 = []
11:57:39 AM Notice  Execution completed

To perserve the value of globalVariable from one execution to the next you need to use PropertyService要将 globalVariable 的值从一次执行保存到下一次执行,您需要使用PropertyService

You have created a web application using Google Apps Script.您已经使用 Google Apps 脚本创建了一个 web 应用程序。 The client-side code calls the server side function createOrGetFolder .客户端代码调用服务器端 function createOrGetFolder You want that this function returns the name of the Folder object assigned to the folder variable.您希望此 function 返回分配给folder变量的文件夹 object 的名称。

Currently the server side function createOrGetFolder on success returns the folder id ( return folder.getId(); ).目前服务器端 function createOrGetFolder成功返回文件夹 id ( return folder.getId(); )。

To get the folder name you could use folder.getName() but changing the return of this function implies to make changes to the client-side code.要获取文件夹名称,您可以使用folder.getName()但更改此 function 的返回意味着对客户端代码进行更改。

One option is to add aa client function to get the folder name.一种选择是添加客户端 function 以获取文件夹名称。 This could be done by calling a server side function using the folder id that currently returns createOrGetFolder .这可以通过使用当前返回createOrGetFolder的文件夹 ID 调用服务器端 function 来完成。 Another way is, to make that createOrGetFolder store the folder name using the Properties Service, the Cache Service, or other store to save the folder name then using a client side function retrieve this value.另一种方法是,让createOrGetFolder使用属性服务、缓存服务或其他存储文件夹名称来存储文件夹名称,然后使用客户端 function 检索此值。 In both options is very likely that the changes to the html / gs files will be minimal but this will not deliver an optimal overall performance of your web application as Google Apps Script services are slow.在这两个选项中,对 html / gs 文件的更改很可能是最小的,但这不会为您的 web 应用程序提供最佳的整体性能,因为 Google Apps 脚本服务很慢。

Another option is to change the createOrGetFolder function return but that implies investing time on studying the client side code and changing multiple lines of code, probably will be more expensive in programmer hours than the first option but might warrant that your web application will have an optimal overall permorance by keeping the calls to the Google Apps Script services at minimum.另一种选择是更改createOrGetFolder function 回报,但这意味着要花时间研究客户端代码和更改多行代码,在程序员时间上可能比第一种选择更昂贵,但可能保证您的 web 应用程序将具有最佳通过将对 Google Apps 脚本服务的调用保持在最低限度来提高整体性能。

Resources资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM