首页 > 解决方案 > 从不同的 HTML 标记中获取多个对应的值以在函数中使用

问题描述

我试图通过按下侧边栏上的按钮来调用函数。

函数应该找到标签的选中复选框并从标签中<input>获取相应的名称<a>

然后它将名称传递给后端 Google Apps 脚本函数(有效)以从工作表中获取一组日历。

然后它将一组名称和日历收集到一个对象中{},并将其传递给另一个后端函数,该函数获取日历事件并将它们写入工作表(这也有效)。

最终结果应该是:将日历中的事件写入工作表(从后端工作)。从侧边栏进行操作时,我没有将事件写在工作表上。

所以我猜这个 importJobs() 函数有一些错误。

    //get button by id, on click run function
    document.getElementById("btn").addEventListener("click", createData)

功能:

//gets an object with 2 arrays: names and calendars
//to pass to backend function and make records to sheet
function createData() {

     //getting all checkboxes
     var allCheckboxes = document.getElementsByClassName("filled-in")
     
     //getting inputs of start and end dates
     var startdate = document.getElementById("startDate").value
     var enddate = document.getElementById("endDate").value
 
     //getting dates as date objects
     var startDate = new Date(startdate)
     var endDate = new Date(enddate)
    
     var chosenNames = []
     
     //getting all <a> tag elements
     var names = document.getElementsByTagName("a")
     
     //converting elements list into array
     var namesArr = Array.from(names)
     
     //looping all checkboxes
     for (var i = 0; i < allCheckboxes.length; i++) {
     
         //getting value of each checkbox
         var checkbox = allCheckboxes[i].value;
         
         //if checkbox is checked
         if (checkbox == true) {         
           
             //getting correspondent employee name
             var name = namesArr[i].value
             
             //and push it to an array
             chosenNames.push(name)
   
         } else {
         
         continue;             
         }
     };
 
   //object with array of chosen names
   var employees = {
   
     names: chosenNames       
   }

   //getting array of cals calling backend function
   var calendars = google.script.run.loopToGetCals(employees)
   
   //putting aray of cals into object
   employees.cals = calendars
 
    //call backend function to get calendar events
   google.script.run.getCalendarEvents(employees, startDate, endDate)
   
}; 

标签: javascripthtmldomgoogle-apps-scriptreturn-value

解决方案


您的客户端代码的一些问题可能隐藏在通信接口的细节中。如评论中所述,某些数据类型无法在 Google Apps 脚本后端和HtmlService客户端前端之间传递。特别值得注意的是Date限制

作为一般规则,除非我传递单个值,否则我通常会将服务器端值序列化为 JSON,然后再将其发送到客户端。这可以确保只传输可序列化的内容(因此不会尝试原始Date对象,也不会尝试原生 Apps Script 类对象)。

此外,我发现这使得返回大响应更加稳定:也许 areturn <large 2D array>偶尔会被视为undefined在客户端,而return JSON.stringify(<same 2D array>)将安全地作为JSON.parse参数到达。

考虑到这一点,您对同步代码的使用需要修改。给定的参数withSuccessHandler应该是函数变量或内联函数定义,例如

...
 .withSuccessHandler(foo)
...

在命名空间的其他地方可以看到

function foo(retVal, uObj) { ... }

或者

const foo = (retVal, uObj) => { ... }; // or const foo = function (retVal, uObj) { ... };

内联语法类似于:

...
  .withSuccessHandler((retVal, uObj) => { ... })
// or
  .withSuccessHandler(function (retVal, uObj) { ... })
...

在所有这些情况下,成功处理程序使用 2 个参数调用 - 服务器端函数的返回值 ( arg1),以及分配给调用的google.script.run任务运行程序的指定“用户对象”( arg2)。

function getCheckedNames() {
  //getting all checkboxes
  const allCheckboxes = Array.from(document.getElementsByClassName("filled-in"));

  //getting all <a> tag elements as a native Array.
  const names = Array.from(document.getElementsByTagName("a"));

  //Reduce from all names to only those that are "checked."
  return allCheckboxes.reduce((arr, cb, i) => {
    // Store the corresponding employee name for any checked checkbox 
    if (cb.value === true)
      arr.push(names[i].value);
    return arr;
  }, []);
}
function requestCheckedCalendars() {
  const chosenNames = getCheckedNames();

  // Submit these names to the backend, to receive their calendar events.
  // Async call, so we will include this object in our call so that the
  // success handler callback can keep working with it.
  google.script.run
    .withUserObject(chosenNames)
    .withSuccessHandler(requestCalendarEvents)
    .loopToGetCals(JSON.stringify({names: chosenNames}));
}
/**
  * @param {string[]} calendars An array of Google Calendar IDs
  * @param {string[]} [chosenNames] An array of names associated with `calendars` (the "user object")
  */
function requestCalendarEvents(calendars, chosenNames) {
  // Convert from JSON-serialized data to native Object types.
  if (typeof calendars === "string")
    calendars = JSON.parse(calendars);
  if (typeof chosenNames === "string")
    chosenNames = JSON.parse(chosenNames);
  if (!chosenNames)
    chosenNames = getCheckedNames();

  const employees = {
    names: chosenNames,
    cals: calendars
  };

  //read inputs of start and end dates
  const startdate = document.getElementById("startDate").value
  const enddate = document.getElementById("endDate").value

  //getting dates as UTC milliseconds
  const startDate = new Date(startdate).getTime();
  const endDate = new Date(enddate).getTime();

  //call backend function to get calendar events
  google.script.run
    // .withSuccessHandler( <some client function> )
    .getCalendarEvents(JSON.stringify(employees), startDate, endDate);
}

其他参考

(理论上,您可以使用Function#bind将一些附加参数预先传递给用作成功处理程序的函数,但我没有对此进行调查。)


推荐阅读