Вероятно, некоторые проблемы с вашим клиентским кодом скрыты в деталях интерфейса связи.Как упоминалось в комментариях, существуют определенные типы данных, которые нельзя передавать между серверной частью скрипта Служб Google и клиентским интерфейсом HtmlService
.Особенно примечательны ограничения Date
.
Как правило, если я не передаю отдельные значения, я обычно сериализую значение на стороне сервера в JSON перед отправкой его клиенту,Это гарантирует, что передаются только сериализуемые объекты (поэтому не предпринимаются попытки ни к необработанным объектам Date
, ни к объектам класса родного скрипта Apps).
Кроме того, я обнаружил, что это делает возврат больших ответов более стабильным: возможно,return <large 2D array>
будет иногда рассматриваться как undefined
на стороне клиента, в то время как return JSON.stringify(<same 2D array>)
будет безопасно доставляться как JSON.parse
способный параметр.
Учитывая это, ваше использование синхронного кода должнобыть исправленоПараметр, заданный для withSuccessHandler
, должен быть либо функциональной переменной, либо определением встроенной функции, например,
...
.withSuccessHandler(foo)
...
, где в другом месте пространства имен можно увидеть
function foo(retVal, uObj) { ... }
или
const foo = (retVal, uObj) => { ... }; // or const foo = function (retVal, uObj) { ... };
Встроенный синтаксис будет похож на:
...
.withSuccessHandler((retVal, uObj) => { ... })
// or
.withSuccessHandler(function (retVal, uObj) { ... })
...
Во всех этих случаях обработчик успеха вызывается с 2 аргументами - возвращаемое значение серверной функции (arg1
),и указанный «пользовательский объект» назначен вызываемому google.script.run
исполнителю задач (arg2
).
function getCheckedNames() {
//getting all checkboxes
const allCheckboxes = Array.from(document.getElementsByClassName("filled-in"));
//getting all <a> tag elements as a native Array.
const names = Array.from(document.getElementsByTagName("a"));
//Reduce from all names to only those that are "checked."
return allCheckboxes.reduce((arr, cb, i) => {
// Store the corresponding employee name for any checked checkbox
if (cb.value === true)
arr.push(names[i].value);
return arr;
}, []);
}
function requestCheckedCalendars() {
const chosenNames = getCheckedNames();
// Submit these names to the backend, to receive their calendar events.
// Async call, so we will include this object in our call so that the
// success handler callback can keep working with it.
google.script.run
.withUserObject(chosenNames)
.withSuccessHandler(requestCalendarEvents)
.loopToGetCals(JSON.stringify({names: chosenNames}));
}
/**
* @param {string[]} calendars An array of Google Calendar IDs
* @param {string[]} [chosenNames] An array of names associated with `calendars` (the "user object")
*/
function requestCalendarEvents(calendars, chosenNames) {
// Convert from JSON-serialized data to native Object types.
if (typeof calendars === "string")
calendars = JSON.parse(calendars);
if (typeof chosenNames === "string")
chosenNames = JSON.parse(chosenNames);
if (!chosenNames)
chosenNames = getCheckedNames();
const employees = {
names: chosenNames,
cals: calendars
};
//read inputs of start and end dates
const startdate = document.getElementById("startDate").value
const enddate = document.getElementById("endDate").value
//getting dates as UTC milliseconds
const startDate = new Date(startdate).getTime();
const endDate = new Date(enddate).getTime();
//call backend function to get calendar events
google.script.run
// .withSuccessHandler( <some client function> )
.getCalendarEvents(JSON.stringify(employees), startDate, endDate);
}
Другие ссылки
(теоретически возможно, что вы могли бы использовать Function#bind
для предварительной передачи некоторых дополнительных аргументов функции, используемой в качестве обработчика успеха, но я не исследовал это.)