数组 returns 在 JS 中为 null 但在 GS 中为 "non-null"

Array returns as null in JS but "non-null" in GS

我正在尝试在网络应用程序上使用 Apps 脚本和 JS 来检索存储在 google sheet 中的信息,然后将其输出到网络应用程序。但是,我不断收到错误消息“无法读取 属性 of null”。

问题是,当我 运行 代码的应用程序脚本端(如下所示)时,我的数组很好,当我将它记录到控制台时,它没有出现问题:snippit 中的代码位于结束

当我 运行 来自网络应用程序的代码时,出现错误。这是 JS 代码:代码片段在末尾

我已将错误缩小到最后一行代码,更具体地说,是 infoArray[i]。它只是作为一个充满“空”的数组出现,即使当我 运行 GS 代码时,它会按原样返回 运行 数组,所有信息都在传播中sheet.

我已经阅读了至少 10 个其他线程,但似乎仍然无法弄清楚为什么这行不通。任何见解将不胜感激!

谢谢

使用 MRE 进行第二次编辑(抱歉,这是一个很长的片段。两个 include-css 文件目前都是空的,代码本身没有用)

JavaScript

document.addEventListener('DOMContentLoaded', function() {
  var elems2 = document.querySelectorAll('.autocomplete');
  var instances2 = M.Autocomplete.init(elems2);
  google.script.run.withSuccessHandler(populateWords).getNames();
})

document.getElementById('loadButton').addEventListener('click', clickGetInfo);

//FOR AUTOCOMPLETE
function populateWords(words) {
  var autocomplete = document.getElementById("autoEmployee");
  var instances = M.Autocomplete.init(autocomplete, {
    data: words
  });
}

function clickGetInfo() {

  var employeeInfo = {};
  employeeInfo.name = document.getElementById('autoEmployee').value;
  google.script.run.withSuccessHandler(updateText).getInfoEdit(employeeInfo);
}

function updateText(infoArray) {
  var elements = ["matricule", "sexe", "civ", "nom", "prenom", "nomJf", "birthday", "nationalite", "adresse", "codePostal", "ville", "pays", "communeNais", "paysNais", "dptNais", "numerosecu", "email",
    "telephone", "shop", "contrat", "hhebdo", "dateDebut", "periodeEssais", "dateFin", "tuteur", "poste", "statut", "echelon", "salaire", "iban", "bic", "domiciliation",
    "primeTel", "primeFroid", "comment", "rqth", "commentRqth", "titreSejour", "numeroTitre", "dateExpiration", "dateIngestion"
  ];

  for (var i = 0; i < elements.length; i++) {
    // console.log(document.getElementById(elements[i]).value);
    // console.log(infoArray);
    document.getElementById(elements[i]).value = infoArray[i];
  }
}

GS


//common vars
var id = '1Sq6f68fjnF3qPfi6guWlSHT84f_UjcFFMnAXwKsqQkM'; // data base

//VARIABLES PAGE HTML
var Route = {};
Route.path= function(route,callback){
  Route[route] = callback;}


// doGet + routes
function doGet(e) {
Route.path("pageEditEmployee",loadEdit);
if(Route[e.parameter.v]){
return Route[e.parameter.v]();
}else{    
return HtmlService.createTemplateFromFile("home").evaluate();}}


// load edit page
function loadEdit(){
  var tmp = HtmlService.createTemplateFromFile("pageEditEmployee"); 
return tmp.evaluate();
}




//CREATION DE LA FONCTION INCLUDE HTML
function include(filename){
return HtmlService.createHtmlOutputFromFile(filename).getContent();}


function getInfoEdit(employeeInfo) {
  var ss = SpreadsheetApp.openById(id);
  var wsData = ss.getSheetByName("DATA");
  var data = wsData.getDataRange().getValues();
  var infoArray = new Array();
  var matricule = employeeInfo.name;
  Logger.log(matricule);
  for (var i = 0; i < data.length; i++) {
    if (data[i][41] == matricule) {
      //[41] for column AP
      var row = i + 1; // row of data
      Logger.log(row);
    }
  }
  for (var i = 1; i < 42; i++) {
    infoArray.push(wsData.getRange(row, i).getValue()); // push data into array
  }
  return infoArray; // return the array
}

// names for AUTOCOMPLETE FOR EDIT PAGE
function getNames() {
  var ss = SpreadsheetApp.openById(id);
  var wsData = ss.getSheetByName("DATA");
  var lastRow = wsData.getRange("A1").getDataRegion().getLastRow();
  var listOfNames = wsData.getRange(2, 42, lastRow - 1, 1).getValues();
  var obj = Object.fromEntries(
    // create object from array
    listOfNames.map((name) => [name, null])
  );
  return obj;
}

HTML 编辑页面

<!DOCTYPE html>
    <html>

    <head>
      <base target="_top">
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
      <?!= include("pageEditEmployee-css");?>
    </head>

    <body>
      <div class="container">
        <div class="row"></div>
        <nav>
          <div class="nav-wrapper lime">
            <a class="brand-logo right">Espace RH</a>
            <ul id="nav-mobile" class="left hide-on-med-and-down">
              <li><a href="<?= ScriptApp.getService().getUrl();?>?v=home"><i class="material-icons left">home</i>Home</a></li>
            </ul>
          </div>
        </nav>

        <div class="container">
          <!-- DIV CONTAINER 1 -->
          <div class="row">
            <div class="col s12">
              <div class="row">
                <div class="input-field col s6">
                  <i class="material-icons prefix">textsms</i>
                  <input type="text" id="autoEmployee" class="autocomplete">
                  <label for="autoEmployee">Take your pick</label>
                </div>
                <div class="input-field col s6">
                  <button id="loadButton" class="btn waves-effect waves-light" type="submit" name="action">Load
                <i class="material-icons right">check_circle</i>
              </button>
                </div>
              </div>
            </div>
          </div>

          <div class="row">
            <div class="input-field col s3">
              <input disabled value="Matricule" id="matricule" type="text" class="validate">
            </div>
            <div class="input-field col s3">
              <input disabled value="Civilité" id="civ" type="text" class="validate">
            </div>
            <div class="input-field col s3">
              <input disabled value="Sexe" id="sexe" type="text" class="validate">
            </div>
            <div class="input-field col s3">
              <input disabled value="Nom" id="nom" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Prénom" id="prenom" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Nom Jeune Fille" id="nomJf" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Date de Naissance" id="birthday" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Nationalité" id="nationalite" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Adresse" id="adresse" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Code Postal" id="codePostal" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Ville" id="ville" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Pays" id="pays" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Commune de Naissance" id="communeNais" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Pays de Naissance" id="paysNais" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Département de Naissance" id="dptNais" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Numéro de sécurité sociale" id="numerosecu" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Email" id="email" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Téléphone" id="telephone" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Atelier" id="shop" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Type de contrat" id="contrat" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Heures Hebdo" id="hhebdo" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Date de début" id="dateDebut" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s3">
              <input disabled value="Fin de la période probatoire" id="periodeEssais" type="text" class="validate">
            </div>
            <div class="input-field col s3">
              <input disabled value="Fin contrat si CDD" id="dateFin" type="text" class="validate">
            </div>
            <div class="input-field col s3">
              <input disabled value="Tuteur ou Tutrice" id="tuteur" type="text" class="validate">
            </div>
            <div class="input-field col s3">
              <input disabled value="Poste" id="poste" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Statut" id="statut" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Echelon" id="echelon" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Salaire" id="salaire" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="IBAN" id="iban" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="BIC" id="bic" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Domiciliation" id="domiciliation" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Prime de téléphone" id="primeTel" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Prime froid" id="primeFroid" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Commentaires primes" id="comment" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="RQTH" id="rqth" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Commentaires RQTH" id="commentRqth" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Titre de séjour" id="titreSejour" type="text" class="validate">
            </div>
          </div>

          <div class="row">
            <div class="input-field col s4">
              <input disabled value="Numéro de titre" id="numeroTitre" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Date expiration" id="dateExpiration" type="text" class="validate">
            </div>
            <div class="input-field col s4">
              <input disabled value="Date d'enregistrement de la personne" id="dateIngestion" type="text" class="validate">
            </div>
          </div>
        </div>
        <!-- END DIV CONTAINER 1 -->

        <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
        <?!= include("pageEditEmployee-js");?>
          <div class="container">
            <footer class="page-footer light-green darken-4 s12">
              <div class="footer-copyright lime">
                <div class="container black-text">
                </div>
              </div>
            </footer>
          </div>
    </body>

    </html>

HTML首页

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
    <?!= include("home-css");?>
  </head>
  <body>


<div class="container">

<div class="row"></div>

<nav>
<div class="nav-wrapper lime">
<a class="brand-logo right"></a>
<ul id="nav-mobile" class="left hide-on-med-and-down">
<li><a href="<?= ScriptApp.getService().getUrl();?>?v=home"><i class="material-icons left">home</i>Accueil</a></li>
</ul>
</div>
</nav>

<div class="row"></div>

<h3 class="card-panel z-depth-3 white-text light-green darken-4">Hello, world</h3>

<div class="row"></div>
<div class="row"><!-- 1ERE LIGNE -->     
    <div class="col s6 m6">
       <div class="card horizontal">
      <div class="card-image">
       <i class="large material-icons">access_time</i>
      </div>
      <div class="card-stacked">
        <div class="card-content">
          <p>My problem is in here</p>
        </div>
        <div class="card-action">
          <a class="green-text" href="<?= ScriptApp.getService().getUrl();?>?v=pageEditEmployee">Click me</a>
        </div>
      </div>
    </div>
  </div>  
  </div>
  </div>
</div><!-- CLOSE CONTAINER -->    

<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
 <div class="container">
 <footer class="page-footer light-green darken-4 s12">
 <div class="footer-copyright lime">
 <div class="container black-text">
 </div>
 </div>
 </footer>
</div>



</body>
</html>

试试这个:

function getInfoEdit(employeeInfo) {
  var ss = SpreadsheetApp.openById(id);
  var dsh = ss.getSheetByName('DATA');
  var data = dsh.getDataRange().getValues()
  var infoArray = [];
  var matricule = employeeInfo.name;
  for (var i = 0; i < data.length; i++) {
    if (data[i][41] == matricule) { //[41] for column AP column 42
      infoArray.push(data[i]);//This pushes the entire row in to your output array
    }
  }
  return (infoArray); // return the array
}

无法确认这些,因为您没有提供 html 但下面的数组中只有 41 个元素。我相信你有 42 列

function updateText(infoArray){
var elements = ["matricule","sexe", "civ", "nom", "prenom", "nomJf", "birthday", "nationalite", "adresse", "codePostal", "ville", "pays", "communeNais", "paysNais", "dptNais", "numerosecu", "email", 
"telephone", "shop", "contrat", "hhebdo", "dateDebut", "periodeEssais", "dateFin", "tuteur", "poste", "statut", "echelon", "salaire", "iban", "bic", "domiciliation", 
"primeTel", "primeFroid", "comment", "rqth", "commentRqth", "titreSejour", "numeroTitre", "dateExpiration","dateIngestion"]; 
  
for (var i = 0;i<elements.length;i++){
  document.getElementById(elements[i]).value = infoArray[i];
  }
}

在尝试你的 MRE 时,我得到了与你完全不同的错误。但至少了解您正在尝试做什么是有帮助的。

我认为问题是:

Requests fail if you attempt to pass a Date, Function, DOM element besides a form, or other prohibited type, including prohibited types inside objects or arrays.

Parameters and return values - Google Documentation

您的数据中包含 Date 对象,因此这将 return 为 null。我认为这是您遇到的错误。

解决方案

所以这里是一个最小可重现的例子,展示了如何将数据作为数组放入前端。

Code.gs

function doGet(){
  return HtmlService.createHtmlOutputFromFile("index")
}

function getInfo() {
  let file = SpreadsheetApp.getActive();
  let sheet = file.getSheetByName("Sheet1");
  let range = sheet.getDataRange();
  let values = range.getValues();

  return JSON.stringify(values);
}

index.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>

    <h1>Hello</h1>
    <button id=main>Run</button>

<script>   
function main(){
  google.script.run.withSuccessHandler(handleInfo).getInfo()
}

function handleInfo(info){
  console.log(JSON.parse(info))
}

const mainButton = document.getElementById("main")
mainButton.addEventListener('click', () => main())
</script>

  </body>
</html>

在网页中按下按钮会在控制台中产生这样的结果:

主要变化:

来自 Apps 脚本(服务器)的 return 值

JSON.stringify([YOUR ARRAY OR OBJECT WITH DATES]);

那么当你在前端收到它时:

JSON.parse([YOUR ARRAY OR OBJECT WITH DATES])

参考资料