передача переменных в функцию с помощью onclick в forEach l oop - Google Apps Script - PullRequest
1 голос
/ 07 марта 2020

Я пытаюсь создать веб-приложение, которое собирает контент для таблицы из электронной таблицы. Для этого я помещаю содержимое электронной таблицы в массив и строю таблицу в JavaScript с forEach L oop. Это прекрасно работает, но я хочу, чтобы одна ячейка в каждом ряду была кликабельной. При щелчке по ячейке я хочу вызвать другую функцию javascript и передать содержимое других ячеек в соответствующей строке в качестве переменных. Я сделал это, добавив ссылку в ячейку, которая вызывает функцию с событием onclick. Когда я щелкаю ячейку, я вижу в журналах консоли, что функция вызывается, но переменные, которые я хотел передать, не определены.

Думаю, проблема в том, что при нажатии на ячейку l oop заканчивается, и переменная больше не определяется. Но я совершенно не знаю обходной путь для этой проблемы.

Мой HTML файл с кодом javascript (я говорю об остальном в разделе // Таблица JS, в значительной степени в конец кода):

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

    <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">

     <style>
      table.centered {
        table-layout: fixed;
        width: 100%;
      }
      td {
       width: 25%;
      }
      div.add-form{
       width: 50%;
      }
    </style>

  </head>
  <body>
    <h1>Buch hinzufügen</h1>
    <div class="add-form">
      <label>Buchtitel: </label><input type="text" id="titel" class="eingabefeld"> <br>
      <label>Buchautor: </label><input type="text" id="autor" class="eingabefeld"> <br>
      <label>Auflage: </label><input type="number" id="auflage" class="eingabefeld"> <br>
      <button id="btn">Hinzufügen</button>
    </div>

    <!-- Tabelle Buchliste -->
     <h1>Buchliste</h1>

        <table class="centered">
        <thead>
          <tr bgcolor="#f0f0f0">
              <th>Buchtitel</th>
              <th>Buchautor</th>
              <th>Auflage</th>
              <th>Status</th>
          </tr>
        </thead>

        <tbody id="table-body">

        </tbody>
      </table>

    <script>

    //Buch hinzufügen JS
    document.getElementById("btn").addEventListener("click",doStuff);

    function doStuff(){
      var titel =  document.getElementById("titel").value;
      var autor =  document.getElementById("autor").value;
      var auflage =  document.getElementById("auflage").value; 

      //validateForm
      if (titel == "" || autor=="" || auflage=="") {
        alert("FEHLER: Alle Felder müssen ausgefüllt sein!");
        return false;
      }

      //passInfoToGoogleScript
      google.script.run.addInfo(titel, autor, auflage);

      //clearInputFields
      document.getElementById("titel").value = "";
      document.getElementById("autor").value = "";
      document.getElementById("auflage").value = "";
    }


    //Table JS
    document.addEventListener("DOMContentLoaded", function(){
        google.script.run.withSuccessHandler(addElementsToTable).getTableData();
      });

      function addElementsToTable(data){
        var tbody = document.getElementById("table-body");

        data.forEach(function(r){
          var row = document.createElement("tr");
          var col1 = document.createElement("td");
          col1.textContent = r[0];
          var col2 = document.createElement("td");
          col2.textContent = r[1];
          var col3 = document.createElement("td");
          col3.textContent = r[2];
          var col4 = document.createElement("td");


          if(r[3]=="nicht verfügbar"){
            console.log("nicht verfügbar erkannt");
            col4.textContent = r[3] + " | Klick zum Zurückgeben";
            col4.setAttribute("style", "background-color: #E40046;color: #ffffff");
          }

          else{
           console.log("verfügbar erkannt");
           var link = document.createElement("a");
           link.setAttribute("onclick", "test(r[0],r[1],r[2])");
           link.textContent = r[3] + " | Klick zum Ausleihen";
           link.setAttribute("style", "color: #ffffff;");
           col4.setAttribute("style", "background-color: #00965E;");
           col4.appendChild(link);
          }

          row.appendChild(col1);
          row.appendChild(col2);
          row.appendChild(col3);
          row.appendChild(col4);
          tbody.appendChild(row);

         });
      }

    function test(titel,autor,auflage) {
        console.log("Test");
        console.log("Titel: " + titel + " | Autor: " + autor + " | Auflage: " + auflage);
      }
    </script>
  </body>
</html>

Сообщение об ошибке: «Uncaught ReferenceError: r не определена в HTMLAnchorElement.onclick»

1 Ответ

2 голосов
/ 07 марта 2020

Не используйте onxyz атрибуты для обработки событий в современных программах. Функция, которую они создают, создается в глобальном масштабе. Ваша переменная r является локальной для вызова функции.

Вместо этого используйте современную обработку событий:

link.addEventListener("click", function() {
    test(r[0], r[1], r[2]);
});

Когда произойдет щелчок, это вызовет test с тогдашним текущие значения в r. Обработчик событий закрывается через r.

Live Пример:

var fakeData = [
    [
        "first row value 0",
        "first row value 1",
        "first row value 2",
        "first row value 3"
    ],
    [
        "second row value 0",
        "second row value 1",
        "second row value 2",
        "nicht verfügbar"
    ],
    [
        "third row value 0",
        "third row value 1",
        "third row value 2",
        "third row value 3"
    ]
];

function test(x, y, z) {
    console.log(x, y, z);
}

var tbody = document.getElementById("the-body");

fakeData.forEach(function(r) {
    var row = document.createElement("tr");
    var col1 = document.createElement("td");
    col1.textContent = r[0];
    var col2 = document.createElement("td");
    col2.textContent = r[1];
    var col3 = document.createElement("td");
    col3.textContent = r[2];
    var col4 = document.createElement("td");

    if(r[3]=="nicht verfügbar"){
        console.log("nicht verfügbar erkannt");
        col4.textContent = r[3] + " | Klick zum Zurückgeben";
        col4.setAttribute("style", "background-color: #E40046;color: #ffffff");
    }

    else{
        console.log("verfügbar erkannt");
        var link = document.createElement("a");
        link.addEventListener("click", function() {
            test(r[0], r[1], r[2]);
        });
        link.textContent = r[3] + " | Klick zum Ausleihen";
        link.setAttribute("style", "color: #ffffff;");
        col4.setAttribute("style", "background-color: #00965E;");
        col4.appendChild(link);
    }

    row.appendChild(col1);
    row.appendChild(col2);
    row.appendChild(col3);
    row.appendChild(col4);
    tbody.appendChild(row);

});

// Subsequent change to the underlying data
fakeData.forEach(function(r) {
    r[0] += " - updated";
    r[1] += " - updated";
    r[2] += " - updated";
});
<table><tbody id="the-body"></tbody></table>

Обратите внимание, что при нажатии отображается обновленные значения r[0] et c.


Если вы хотите, чтобы функция использовала текущие значения значений в r (по состоянию на момент создания функции, а не при нажатии), вместо этого вы должны использовать bind:

link.addEventListener("click", test.bind(null, r[0], r[1], r[2]));

Принимает значения с момента создания функции.

Live Пример:

var fakeData = [
    [
        "first row value 0",
        "first row value 1",
        "first row value 2",
        "first row value 3"
    ],
    [
        "second row value 0",
        "second row value 1",
        "second row value 2",
        "nicht verfügbar"
    ],
    [
        "third row value 0",
        "third row value 1",
        "third row value 2",
        "third row value 3"
    ]
];

function test(x, y, z) {
    console.log(x, y, z);
}

var tbody = document.getElementById("the-body");

fakeData.forEach(function(r) {
    var row = document.createElement("tr");
    var col1 = document.createElement("td");
    col1.textContent = r[0];
    var col2 = document.createElement("td");
    col2.textContent = r[1];
    var col3 = document.createElement("td");
    col3.textContent = r[2];
    var col4 = document.createElement("td");

    if(r[3]=="nicht verfügbar"){
        console.log("nicht verfügbar erkannt");
        col4.textContent = r[3] + " | Klick zum Zurückgeben";
        col4.setAttribute("style", "background-color: #E40046;color: #ffffff");
    }

    else{
        console.log("verfügbar erkannt");
        var link = document.createElement("a");
        link.addEventListener("click", test.bind(null, r[0], r[1], r[2]));
        link.textContent = r[3] + " | Klick zum Ausleihen";
        link.setAttribute("style", "color: #ffffff;");
        col4.setAttribute("style", "background-color: #00965E;");
        col4.appendChild(link);
    }

    row.appendChild(col1);
    row.appendChild(col2);
    row.appendChild(col3);
    row.appendChild(col4);
    tbody.appendChild(row);

});

// Subsequent change to the underlying data
fakeData.forEach(function(r) {
    r[0] += " - updated";
    r[1] += " - updated";
    r[2] += " - updated";
});
<table><tbody id="the-body"></tbody></table>

Обратите внимание, что при нажатии он видит значения r[0] et c. как это было при создании обработчика щелчков.

I подозреваю вы хотите последний (с bind), но есть варианты использования для обоих.


Примечание: вместо установки атрибута style вы можете напрямую работать с его отраженным свойством. Например, это:

col4.setAttribute("style", "background-color: #E40046;color: #ffffff");

полностью заменяет встроенные стили на элементе (например, удаляя любые, которые были там ранее). Если ты этого хочешь, отлично; в противном случае вы можете сделать:

col4.style["background-color"] = "#E40046"; // Notice the [""] syntax
col4.style.color = "#ffffff";

или

col4.style.backgroundColor = "#E40046"; // Notice no "-" and a capital C
col4.style.color = "#ffffff";
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...