Может ли библиотека скриптов Google Spreadsheet Apps содержать диалог пользователя?
Существуют ли ограничения на то, что может быть в библиотеке скриптов приложений, которая будет использоваться таблицами Google? В частности, может ли библиотека включать HTML-диалог?
Я создал скрипт электронной таблицы, который добавляет пункт меню, чтобы предоставить пользователю диалоговое окно. Оно использует HtmlService.createHtmlOutputFromFile('mappingForm').setSandboxMode(HtmlService.SandboxMode.IFRAME)
как описано в https://developers.google.com/apps-script/guides/html/communication. HTML-файл включает в себя HTML, CSS и JavaScript с jQuery. Оно использует google.script.run
заполнить диалог данными из электронной таблицы и отправить в нее форму.
Это все прекрасно работает в оригинальной таблице.
Однако мне нужно несколько таблиц, чтобы использовать один и тот же код, поэтому я пытаюсь следовать общей идее сценариев Google Spreadsheet, распространяемых по таблицам (не библиотекам), чтобы иметь основной сценарий с шаблоном электронной таблицы и несколькими копиями.
Я следовал инструкциям на https://developers.google.com/apps-script/guide_libraries чтобы создать библиотеку из исходной электронной таблицы. Когда другая электронная таблица использует библиотеку, я могу отобразить диалоговое окно, но все обратные вызовы на сервер (либо для заполнения диалогового окна, либо для отправки формы) завершаются ошибкой с ошибкой, обнаруженной на стороне браузера google.script.run.withFailureHandler
как Error
объект со свойствами:
message: "We're sorry, a server error occurred. Please wait a bit and try again."
name: "ScriptError"
Я поместил вызовы Logger в скрипт приложения, чтобы увидеть, вызываются ли функции на стороне сервера, но ни одна из них не срабатывает. Стенограмма выполнения редактора скриптов показывает:
[14-12-27 19: 38: 05: 340 PST] Начало выполнения
[14-12-27 19:38:05:372 PST] Ошибка выполнения: извините, произошла ошибка сервера. Пожалуйста, подождите немного и попробуйте снова. [0,0 секунд всего времени выполнения]
Клиент выполняет вызов, но что-то не удается, прежде чем он достигнет сценария электронной таблицы.
Это заставляет меня задуматься,
- Мне нужно сделать что-то по-другому, чтобы код работал как библиотека.
- В библиотеках не может быть диалогов.
- Есть ошибка сервера.
Спасибо заранее за любые предложения.
1 ответ
Я смог получить рабочую библиотеку, содержащую диалог HTML, выполнив следующее.
Переместите сценарий и файлы HTML из исходной электронной таблицы в отдельный проект сценария. Обратите внимание на ключ проекта библиотеки на вкладке " Информация " в меню "Файл"> "Свойства проекта...". Это понадобится любой электронной таблице, которая намеревается использовать библиотеку.
Если автономный проект сценария предназначен для использования другими, нажмите кнопку " Поделиться", чтобы сделать его доступным для всех, у кого есть ссылка, иначе он молча потерпит неудачу для них.
Если HTML-диалог должен вызывать функцию библиотеки (для получения или отправки данных), функция библиотеки должна присутствовать в электронной таблице, которая использует библиотеку, или вы получите сообщение об ошибке в консоли JavaScript браузера.
В электронной таблице, которая использует библиотеку: Инструменты> Редактор сценариев... Нажмите Ресурсы> Библиотеки.... В диалоговом окне "Включенные библиотеки" введите ключ автономного проекта в текстовом поле " Найти библиотеку", нажмите " Выбрать", затем выберите соответствующую версию, при необходимости измените идентификатор и сохраните. Значение идентификатора создает объект с тем же именем для использования сценарием электронной таблицы для вызова функций библиотеки. В моем случае это
SignupFormResponsesSheet
,В том же редакторе кода редактора сценариев добавьте функции-оболочки, которые вызывают функции библиотеки, в том числе те, которые будут вызываться из диалога HTML. В моей библиотеке есть
onOpen()
который создает два пункта меню для отображения диалогов HTML, поэтому я добавил
function onOpen() {
SignupFormResponsesSheet.onOpen();
}
function showMappingForm() {
SignupFormResponsesSheet.showMappingForm();
}
function showSubmitForm() {
SignupFormResponsesSheet.showSubmitForm();
}
- Мой HTML-диалог имеет несколько обратных вызовов для получения и отправки данных, поэтому вместо написания функции-обертки для каждой из них я добавил одну функцию, чтобы охватить все из них, воспользовавшись тем, как сценарий Apps обрабатывает библиотеку как объект, содержащий функции. Первый аргумент - это строка с именем библиотечной функции для вызова. Любые дополнительные аргументы передаются в библиотечную функцию.
function runSignupFormResponseFunction(funcName, varargs) {
return SignupFormResponsesSheet[funcName].apply(this,
Array.prototype.slice.call(arguments, 1));
}
- Из-за ограничения, определенного на шаге 3 выше, JavaScript в диалоге HTML использует google.script.run для вызова
runSignupFormResponseFunction
всякий раз, когда необходимо получить или представить данные. Например, у него есть два списка, которые динамически заполняются данными сервера из библиотеки.getRangeLabels
а такжеgetColumnExamples
функции (и одна должна быть заполнена до другой), поэтому код
google.script.run
.withFailureHandler(showError)
.withSuccessHandler(function(ranges) {
loadRanges(ranges);
// once ranges are loaded, load columns
google.script.run
.withSuccessHandler(loadColumns)
.withFailureHandler(showError)
.runSignupFormResponseFunction("getColumnExamples");
})
.runSignupFormResponseFunction("getRangeLabels");
Это сработало для меня сегодня. Я надеюсь, что это работает для тех, кто может найти этот вопрос.