#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 для проверки тегов, но это не помогает проверять логику так сильно, как отладчик.