You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Google Apps Script中google.script.run.withSuccessHandler返回数组初始硬编码值而非更新后值的问题

Google Apps Script中google.script.run.withSuccessHandler返回数组初始硬编码值而非更新后值的问题

看起来你遇到的核心问题是Google Apps Script(GAS)的服务器端执行环境是无状态的——每次通过google.script.run调用服务器函数时,都会启动一个全新的执行上下文。这意味着你在apresenteCaixaDialogoDataTurno里通过putDatasputTurnos修改的全局数组,在后续调用getDatasgetTurnos时根本不存在,因为这两次调用是完全独立的执行环境,全局变量会被重新初始化为硬编码的默认值。

为什么会这样?

GAS的服务器端代码不是长期运行的后台服务,每一次函数调用都是孤立的。你在打开对话框前修改了全局数组,但这个修改只存在于apresenteCaixaDialogoDataTurno执行的那个临时上下文里。当客户端再调用getDatas时,服务器会重新加载整个脚本,重新定义let datas = ['08/24/2025', '09/24/2025'],自然返回的是初始硬编码值。

解决方案

这里有两种直接可行的解决思路,推荐第一种(更高效且无状态管理隐患):

方案一:打开对话框时直接把数据注入到客户端HTML

不需要后续调用getDatasgetTurnos,而是在初始化对话框时就把需要的数据传递给HTML模板,一次性完成渲染。

  1. 修改服务器端的apresenteCaixaDialogoDataTurno函数
const apresenteCaixaDialogoDataTurno = (dataDados, turnoDados) => {
  // 使用HTML模板替代直接加载文件,这样可以注入数据
  const htmlTemplate = HtmlService.createTemplateFromFile('CaixaDialogoBootstrap');
  // 把要传递的数据赋值给模板变量
  htmlTemplate.datas = dataDados;
  htmlTemplate.turnos = turnoDados;
  
  const html = htmlTemplate.evaluate()
    .setWidth(400)
    .setHeight(300);
  SpreadsheetApp.getUi().showModalDialog(html, 'Selecione a Data e o Turno');
}
  1. 修改客户端HTML(CaixaDialogoBootstrap)
    在页面加载时直接用模板传递的数据初始化下拉框:
<!-- 保留你原有的select元素 -->
<select class="form-select form-select-lg mb-3" aria-label=".form-select-lg example" id="datasSuspensasId" onchange="obtenhaDataSelecionada()">
</select>
<select class="form-select form-select-lg mb-3" aria-label=".form-select-lg example" id="turnosSuspensosId" onchange="obtenhaTurnoSelecionado()">
</select>

<script>
// 页面加载完成后立即初始化下拉框
document.addEventListener('DOMContentLoaded', function() {
  // 用模板变量填充数据,JSON.stringify确保数组正确传递
  atualizeDatas(<?= JSON.stringify(datas) ?>);
  atualizeTurnos(<?= JSON.stringify(turnos) ?>);
});

// 保留你原有的所有客户端函数
function atualizeDatas(dados) {
  atualizeSelect('datasSuspensasId', 'Escolha uma data', dados);
}

function atualizeTurnos(dados) {
  atualizeSelect('turnosSuspensosId', 'Escolha um turno', dados);
}

function atualizeSelect(elementoId, aviso, dados) {
  const dropdown = document.getElementById(elementoId);
  dropdown.innerHTML = ''; // 清空现有选项
  dropdown.innerHTML = `<option selected>` + aviso + `</option>`
  dados.forEach(item => {
    const option = document.createElement('option');
    option.value = item;
    option.textContent = item;
    dropdown.appendChild(option);
  });
}

// 保留你其他的客户端逻辑,比如obtenhaDataSelecionada等
// ...
</script>

方案二:用PropertiesService存储共享状态(适合需要动态更新数据的场景)

如果你的数据需要在对话框打开后动态更新,必须通过后续服务器调用获取,那可以用GAS的PropertiesService来存储数据,替代全局变量,实现跨执行上下文的状态共享。

  1. 修改服务器端的put/get函数
// 用脚本属性存储数据,替代全局变量
const putDatas = (dados) => {
  // 把数组转成JSON字符串存储
  PropertiesService.getScriptProperties().setProperty('datas', JSON.stringify(dados));
};

const getDatas = () => {
  const storedData = PropertiesService.getScriptProperties().getProperty('datas');
  // 如果没有存储数据,回退到硬编码初始值
  return storedData ? JSON.parse(storedData) : ['08/24/2025', '09/24/2025'];
};

const putTurnos = (dados) => {
  PropertiesService.getScriptProperties().setProperty('turnos', JSON.stringify(dados));
};

const getTurnos = () => {
  const storedData = PropertiesService.getScriptProperties().getProperty('turnos');
  return storedData ? JSON.parse(storedData) : [];
};

const apresenteCaixaDialogoDataTurno = (dataDados, turnoDados) => {
  putDatas(dataDados);
  putTurnos(turnoDados);
  
  const html = HtmlService.createHtmlOutputFromFile('CaixaDialogoBootstrap')
    .setWidth(400)
    .setHeight(300);
  SpreadsheetApp.getUi().showModalDialog(html, 'Selecione a Data e o Turno');
}
  1. 客户端代码不需要修改,原来的google.script.run.withSuccessHandler(atualizeDatas).getDatas();调用现在会正确返回存储的更新后数据。

注意事项

  • 如果是多用户使用的脚本,方案二的getScriptProperties()是全局共享的,可能会导致数据冲突,这时候应该用getUserProperties()来存储用户专属的数据。
  • 方案一的性能更好,减少了一次服务器往返调用,是大多数场景的最优解。

内容来源于stack exchange

火山引擎 最新活动