Получать значения имен и ссылок при зацикливании HTML-элементов с помощью Javascript

#javascript #html #google-apps-script

#javascript #HTML #google-apps-script

Вопрос:

Я создаю веб-приложение для электронной таблицы для боковой панели.

Попытка обработать прослушиватель событий, который реализует эти условия:

  • при установке флажков (которые имеют соответствующие имена и ссылки на календарь для этих имен)
  • и выбирать 2 даты
  • а затем нажимать кнопку

После того, как все это сделано, из серверной части вызывается функция, которая получает события для этих имен и записывает их в таблицу.

Я не могу получить значения для имен и календарей в цикле. И не уверен, какой хороший способ их разместить. Я пытался справиться с этим разными способами — безуспешно.

В конечном итоге я сузил все проблемы до этих двух частей:

1) как наилучшим образом загрузить данные на боковую панель.

2) как выполнить цикл по этим данным после взаимодействия пользователя с этими элементами и получить значения (зависит от части 1).

Я был бы очень признателен, если бы кто-нибудь помог мне немного подробнее с этим (некоторые довольно простые решения).

Вот вариант со скриптлетами для использования GAS в html-файле:

 <? for (var i = 0; i < loopNamesForSidebar().names.length; i  ) {  ?>
    <label>
       <input type="checkbox" class="filled-in check" checked="checked" />
       <span>
         <div class="collection">     
           <a href=" <?= loopNamesForSidebar().calendars[i] ?>" class="collection-item" >
             <?= loopNamesForSidebar().names[i]  ?>
           </a>
         </div>
       </span>
<? } ?>
    </label>
  

loopNamesForSidebar() это серверная функция, которая зацикливает имена и календари, которые переходят на боковую панель. Каждый раз, когда я открываю боковую панель, эти данные обновляются. У меня это не используется в моей интерфейсной части.

Вот код Javascript в HTML-файле:

    //import jobs from calendars to sheet 
function importJobs() {
  //getting all checkboxes
  var allCheckboxes = document.getElementsByClassName("check")

  //getting inputs of start and end dates
  var startDate = document.getElementById("startDate").value
  var endDate = document.getElementById("endDate").value

  var chosenNames = []
  var calendars = []

  //looping all checkboxes
  for (var i = 0; i < allCheckboxes.length; i  ) {
    //getting value of each checkbox
    var checkbox = allCheckboxes[i].checked;

    //if checkbox is checked
    if (checkbox == true) {
      //getting correspondant employee name
      var name = loopNamesForSidebar().names[i]

      //and push it to an array
      chosenNames.push(name)

      //getting correspondant employee calendar
      var cal = loopNamesForSidebar().calendars[i]
      calendars.push(cal)

    } else {
      continue;
    }
  };

  //push names and cals to object
  var employees = {
    names: chosenNames,
    cals: calendars
  }

  //call function to get calendar events
  google.script.run.getEvents(employees, startDate, endDate)
};
  

Комментарии:

1. Для начала, у вас будет намного лучшая производительность, если вы просто вызовете loopNamesForSidebars один раз. Ваша версия скриптлета часто вызывает его целиком. Также обратите внимание, что скриптлеты применимы только при оценке исходного HtmlTemplate объекта — они не вычисляются динамически во время загрузки вашей боковой панели.

2. Верно! Выполнение действительно медленное. Итак, вы говорите, что использовать скриптлеты для получения элементов — плохая практика? Спасибо за совет.

3. Это означает, что вы не можете использовать серверную функцию, определенную в gs, loopNamesForSidebar в вашей клиентской функции importJobs . Вы можете вызвать это через google.script.run и получить результаты в любом обработчике успеха , который вы привязываете к google.script.run вызову.

4. Настоятельно рекомендуется загружать только статическое содержимое в ваш исходный HtmlTemplate / HtmlOutput — т. Е. только то, что извлекается из PropertiesService или CacheService или тривиально вычисляется на основе входных doGet / doPost параметров. Все, что требует вызова API / Service, должно загружаться асинхронно. developers.google.com/apps-script/guides/html /…

5. Причина, по которой я зацикливал эти имена при каждом открытии боковой панели, заключается в том, что эти данные время от времени меняются. Некоторые люди приходят и уходят, и я не могу использовать статистические данные раз и навсегда. Я хочу убедиться, что я открываю боковую панель, и данные там всегда актуальны, и мне не нужно помнить, чтобы каким-то образом перезагружать их там и т.д.

Ответ №1:

Согласно рекомендациям, вы должны загружать любой вывод вызова API / ___ Service асинхронно. Я бы использовал оценку шаблона только для тривиально вычисленных / извлеченных данных, например, из PropertiesService , CacheService статических определений или простых поисковых запросов на основе входных параметров (т. Е. данных строки запроса / полезной нагрузки для doGet и doPost функций запуска). Если в среднем это занимает больше четверти секунды, это слишком медленно для синхронного использования.

итак:

 function templateOK(param) {
  const val = PropertiesService.getScriptProperties().getProperty(param);
  return val ? JSON.parse(val) : [
    "name 1", "name 2", "name 3"
  ];
}
function shouldRunAsync(param) {
  const sheet = param ? SpreadsheetApp.getActive().getSheetByName(param) : null;
  return sheet ? sheet.getDataRange().getValues() : [];
}
  

Предполагая, что вы соответствующим образом настроили другие части ваших файлов GS и HTML, один из <script> тегов .html может выглядеть примерно так:

 $(document).ready(() => loadServerData()); // jQuery
function loadServerData() {
  const TASK = google.script.run.withSuccessHandler(useNames); // has implicit failure handler of `console`
  // Schedule this to be run every so often
  const intervalMS = 10 * 60 * 1000; // 10 minutes
  setInterval(sheetName => TASK.shouldRunAsync(sheetName), intervalMS, "Names");
  // Invoke promptly too.
  TASK.shouldRunAsync("Names");
  console.log(new Date(), "Set schedule amp; invoked server function");
}
function useNames(serverValue, userObject) {
  console.log(new Date(), "Got Value from server", serverValue);
  // use the return value to do stuff, e.g.
  const cbDiv = $("id of div containing checkboxes"); // jQuery
  /** could add code here to read existing checkbox data, and
      use that to maintain checked/unchecked state throughout loads */
  cbDiv.innerHTML = serverValue.map((name, idx) => `<p id="${name}">${idx   1}: ${name}</p>`).join("");
}
  

Как всегда, убедитесь, что вы хорошо знакомы с сериализуемыми типами данных и моделью взаимодействия клиент-сервер:https://developers.google.com/apps-script/guides/html/communication

Другие ссылки

Комментарии:

1. Большое вам спасибо @tehhowch!!! Вы очень помогли, сэкономив дни напрасной практики))

2. Как вы тестируете и отлаживаете HTML-часть? Я использую средство проверки html для проверки тегов, но это не помогает проверять логику так сильно, как отладчик.