如何在对话框关闭时通知Google Apps Script自定义侧边栏?
解决方法:让对话框主动回传数据给侧边栏
你遇到的问题确实很典型——google.script.run的withSuccessHandler会在对话框显示时就触发,因为showModalDialog是异步执行的,服务器端的showTemplatedDialog函数在调用完ui.showModalDialog()后就立刻执行完毕了,根本不会等待对话框关闭。
下面是一套可靠的解决方案,核心思路是让对话框在用户完成操作(或关闭前)主动把数据发送到服务器暂存,再让侧边栏通过轮询获取结果:
步骤1:修改服务器端代码(code.gs)
先添加两个辅助函数用来暂存和读取对话框返回的数据,同时保留你原有的对话框显示逻辑:
// 暂存对话框返回的数据(存在用户专属属性中,避免多用户冲突) function setDialogResult(data) { PropertiesService.getUserProperties().setProperty('DIALOG_RESULT', JSON.stringify(data)); } // 获取并清空暂存的对话框数据 function getDialogResult() { const props = PropertiesService.getUserProperties(); const result = props.getProperty('DIALOG_RESULT'); props.deleteProperty('DIALOG_RESULT'); // 清空数据,避免重复读取 return result ? JSON.parse(result) : null; } // 你的原有对话框显示函数(调整参数适配需求) function showTemplatedDialog(dialogName, dialogData, width, height, title) { var htmlTemplate = HtmlService.createTemplateFromFile(dialogName); htmlTemplate.dataFromServerTemplate = dialogData; var html = htmlTemplate.evaluate() .setSandboxMode(HtmlService.SandboxMode.IFRAME) .setWidth(width) .setHeight(height); var ui = SpreadsheetApp.getUi(); ui.showModalDialog(html, title); }
步骤2:修改对话框的HTML页面
假设你的对话框HTML文件是Dialog.html,添加用户操作按钮,并在点击时发送数据到服务器后关闭对话框:
<!DOCTYPE html> <html> <body> <!-- 你的对话框内容,比如输入框、选择器等 --> <input type="text" id="userInput" placeholder="输入内容"> <button onclick="sendResultAndClose()">确认</button> <script> // 收集用户数据,发送到服务器后关闭对话框 function sendResultAndClose() { const userData = { input: document.getElementById('userInput').value, // 可添加更多用户选择的数据 }; google.script.run .withSuccessHandler(() => google.script.host.close()) .withFailureHandler(err => { console.error('发送数据失败:', err); alert('出错了,请重试'); }) .setDialogResult(userData); } // 可选:监听对话框关闭事件(用户点击右上角叉号时),发送取消标记 window.addEventListener('unload', () => { google.script.run.setDialogResult({canceled: true}); }); </script> </body> </html>
步骤3:修改侧边栏的代码
在侧边栏调用对话框后,启动轮询定期检查服务器是否有对话框返回的数据:
<!-- 侧边栏HTML页面,比如Sidebar.html --> <!DOCTYPE html> <html> <body> <button onclick="openDialog()">打开对话框</button> <script> let pollInterval; // 存储轮询定时器ID function openDialog() { // 调用服务器打开对话框 google.script.run .withFailureHandler(errorHandler) .showTemplatedDialog('Dialog', {}, 300, 200, '我的对话框'); // 启动轮询,每500毫秒检查一次结果 pollInterval = setInterval(checkDialogResult, 500); } // 检查服务器中的对话框返回数据 function checkDialogResult() { google.script.run .withSuccessHandler(handleDialogResult) .withFailureHandler(err => { console.error('获取数据失败:', err); clearInterval(pollInterval); }) .getDialogResult(); } // 处理对话框返回的数据 function handleDialogResult(result) { if (result) { clearInterval(pollInterval); // 拿到结果后停止轮询 if (result.canceled) { console.log('用户取消了对话框'); // 处理取消逻辑 } else { console.log('用户选择的数据:', result); editDone(result); // 调用你原有的成功处理函数 } } } // 你的原有错误处理函数 function errorHandler(err) { alert('出错了: ' + err.message); clearInterval(pollInterval); } // 你的原有成功处理函数 function editDone(data) { // 自定义处理数据的逻辑 alert('收到对话框数据: ' + JSON.stringify(data)); } </script> </body> </html>
方案优势
- 对话框主动推送数据,确保侧边栏能获取到用户的真实操作结果;
- 用
PropertiesService暂存数据,避免多用户之间的冲突; - 轮询逻辑简单可靠,适合大多数场景,也能覆盖用户主动关闭对话框的情况。
内容的提问来源于stack exchange,提问作者Aidan
相关产品推荐
相关产品推荐

