将 Map 对象发送到 Apps 脚本服务器时出现“TypeError:由于属性中的非法值而失败:0”

问题描述 投票:0回答:1

我正在开发一个绑定到电子表格的 Google Apps 脚本项目。对于某些功能,我显示一个模式对话框,如下所示:模式对话框。因此,一系列数量可变的选择器根据某些数据动态创建和加载。每个选择器都包含在

  • 无序列表的 列表元素中:
    <menu id="categories"></menu>

    单击“确定”按钮后,将调用某个函数;这是 HTML 元素:

    <!-- An 'Ok' button to continue. -->
    <input type="button" value="Ok" onclick="endDialog()" />
    

    现在,此函数 endDialog 从选择器中提取数据,并构建一个 Map 对象和一个数组,然后将其作为参数传递给服务器端 Apps 脚本函数。

    问题来了:endDialog 函数正确执行所有操作,直到

    google.script.run.applyColouring(rowPairs, colourAvailabilities);
    ,此时我收到标题中描述的未捕获错误:

    类型错误:由于属性中的非法值而失败:0

    Error

    以下是一些见解:

    • 问题出在 Map 对象部分(rowPairs),因为当在服务器端函数中仅使用数组参数(colourAvailities)时,一切都运行良好。
    • 服务器端函数永远不会被调用:它永远不会显示在Apps脚本“执行”选项卡中。此外,每当我使用完全相同的参数直接在 Apps 脚本端运行此服务器端函数时,它都会按预期工作。
    • Map 对象已正确构建,或者至少这是我在将其登录到控制台时推断出的:Map 对象
    • 当我修改代码以使用对象而不是映射时,它突然起作用了。所以我可以让它工作,但此时我只是好奇,我想知道到底发生了什么。此外,地图 - 而不是普通的对象 - 正是我所需要的,因为(除其他外)我正在处理数字。
    • 我想知道问题是否在于无法将 Map 作为参数传递给服务器端函数,但文档似乎没有表明这一点:

    合法参数和返回值是 JavaScript 原语,如 Number、Boolean、String 或 null,以及由原语、对象和数组组成的 JavaScript 对象和数组。页面内的表单元素作为参数也是合法的,但它必须是函数的唯一参数,并且作为返回值是不合法的。如果您尝试传递除表单之外的日期、函数、DOM 元素或其他禁止类型(包括对象或数组内的禁止类型),请求将失败。创建循环引用的对象也会失败,数组中未定义的字段将变为空。

    • 我不再确定了,但我发誓两天前我测试最终版本时一切正常。我不确定从那时起我可以修改什么。

    这是整个 HTML 端函数 endDialog:

      /**
       * Calls a server-side function to apply the changes \
       * to the categories' colours and closes the dialog.
       * 
       * @return {void} Nothing.
       */
      function endDialog() {
        // Hide the error messages.
        document.getElementById("emptyColour").style = "display:none;";
        document.getElementById("repeatedColour").style = "display:none;";
        // Get the list of categories.
        const categories = Array.from(document.getElementById("categories").children);
        // Create a map to contain the list of category-colour pairs.
        const rowPairs = new Map();
        // Create an array to contain the column of boolean values
        // corresponding to the availabilities of each colour palette.
        // Initialise all colours as being available.
        const colourAvailabilities = Array.from({length:10}).map(() => [true]);
        // A variable to see if all colours have been selected properly.
        var validSelects = true;
        // A variable to see if all colours are different from each other.
        var uniqueSelects = true;
        // Initialise an index variable to go through the categories.
        var i=0;
        // While the colours are validly selected,
        // and unique, go through the categories.
        while (validSelects && uniqueSelects && i<categories.length) {
          // Get the corresponding row number,
          let catRow = Number(categories[i].value);
          // and its chosen colour's row number.
          let colourRow = Number(document.getElementById(i+1)
                                         .value
                                         .split(',')[0]);
          // Check if the selected option is a valid colour.
          validSelects = colourRow != 0;
          // If the selected option is a valid colour,
          if (validSelects) {
            // set the corresponding colour to being unavailable.
            colourAvailabilities[colourRow-6][0] = false;
            // Add the rows pair to the map.
            // Use the colour row number as the key, so as to easily check whether the
            // number of categories and the number of key-value pairs in the map are equal.
            // Indeed, if this colour has already been used, no new key-value pair will
            // be added, instead just updating the value associated to the colour's row key.
            rowPairs.set(colourRow, catRow);
            // Check if all selected colours are different from each other.
            uniqueSelects = rowPairs.size == i+1;
          }
          // Go to the next category.
          i++;
        }
        // If the user has made a valid and unique colour selection,
        if (validSelects && uniqueSelects) {
          console.log(rowPairs, colourAvailabilities);
          // call a server-side function to apply the changes.
          google.script.run.applyColouring(rowPairs, colourAvailabilities);
          // Close the dialog.
          google.script.host.close();
        }
        // If one of the selected colours is invalid,
        else if (!validSelects) {
          // display an error message.
          document.getElementById("emptyColour").style = "display:block;";
        }
        // If some colour has been selected more than once,
        else {
          // display an error message.
          document.getElementById("repeatedColour").style = "display:block;";
        }
      }
    

    我认为我没有必要共享其余代码,但如果您想要/需要服务器端功能代码或整个 HTML 文件,我可以发布它们。

    如果有人知道问题是什么,我洗耳恭听!预先感谢。

    您无法通过

    Map
    接口发送
    google.script.run
    对象,因为地图无法序列化

    来自文档

    没有对序列化或解析的本机支持。(但是您可以通过使用

    Map
    及其
    replacer
    参数,以及使用 JSON.stringify() 及其
    reviver
    参数来构建对 JSON.parse() 的自己的序列化和解析支持。请参阅Stack Overflow 问题如何 JSON.stringify 一个 ES6 映射?)。

    因此,要么使用普通的

    Object
    ,要么使用您自己的
    replacer
    reviver
    函数在发送端使用
    Map
    和接收端 JSON.stringify() 序列化 JSON.parse()

  • javascript dictionary google-apps-script web-applications typeerror
    1个回答
    0
    投票

    您无法通过

    Map
    接口发送
    google.script.run
    对象,因为地图无法序列化

    来自文档

    没有对序列化或解析的本机支持。(但是您可以通过使用

    Map
    及其
    replacer
    参数,以及使用 JSON.stringify() 及其
    reviver
    参数来构建对 JSON.parse() 的自己的序列化和解析支持。请参阅Stack Overflow 问题如何 JSON.stringify 一个 ES6 映射?)。

    因此,要么使用普通的

    Object
    ,要么使用您自己的
    replacer
    reviver
    函数在发送端使用
    Map
    和接收端 JSON.stringify() 序列化 JSON.parse()

    © www.soinside.com 2019 - 2024. All rights reserved.