提示用户输入 .gs 函数中的范围,将数组传递给 html 脚本并重新关注 HTML 对话框

Posted

技术标签:

【中文标题】提示用户输入 .gs 函数中的范围,将数组传递给 html 脚本并重新关注 HTML 对话框【英文标题】:Prompt user for range in .gs function, pass array to html script and re-focus on the HTML dialog 【发布时间】:2017-07-28 21:01:15 【问题描述】:

我有一个谷歌表,我想提示用户选择范围以从中获取信息,将其存储到一个数组中,然后在一个 html 弹出窗口中创建一个图表。我已经阅读了一些关于 google.script.run 功能的信息,并且了解如果没有最后的 withSuccessHandler(HTMLFunction).FunctionToCall() 语法,HTML 脚本将移至下一行。我在下面有一个 .gs 文件和一个 .html 文件,当我刚刚在 .gs 函数中输入一个静态数组时,我能够使图表工作。但是,我似乎在努力解决如何将焦点返回到编辑器以获取范围,然后将带有图表的 HTML 对话框备份并为绘制图表的函数获取正确的数据。我看到here 我可以使用 google.script.host 来调用 editor.focus() 函数,以便用户现在可以选择单元格,但是如果不调用HTML 文件重新开始。这是我的 .gs 函数:

function RetrieveData()
  var ss = SpreadsheetApp.getActive();
  var sheets = ss.getSheets();
  var s = sheets[1];
  var UI = SpreadsheetApp.getUi();
  var response = UI.prompt("Please enter the first cell in the category").getResponseText();
  var ir = s.getRange(response);
  var n= 0;
  var stored = [];
  stored.push(["Income Category", "Frequency"]);
  while (ir.getValue()!= "") 
   n = n +1;
   ir = ir.offset(1, 0);
   
ir = ir.offset(-n,0)

   for(i =0; i<n;i++) 
    stored.push([ir.getValue(),ir.offset(n+2,0).getValue()]);
    ir = ir.offset(1, 0);
   
return stored;
     

这是我在正文中的 html(Stack Overflow 有点严格,所以我不打算麻烦显示所有 HTML;这只是在正文中,它是与.gs 文件):

google.charts.load('current', 'packages':['corechart']);
google.charts.setOnLoadCallback(getdata);
function getdata() 
      google.script.run.withSuccessHandler(drawChart).RetrieveData();
      google.script.host.editor.focus();
    
  function drawChart(stored) 
   //This apparently shows a log of the object
   //console.log(stored);
   var data = new google.visualization.arrayToDataTable(stored);
   console.log(data);
   var options = 'title':'Income',
                   'width':400,
                   'height':300,
                   'is3d':true;
    // Instantiate and draw our chart, passing in some options.
   var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
   chart.draw(data, options);
google.script.run.withSuccessHandler(drawChart).RetrieveData();
  

我尝试的最后一件事是调用 SpreadsheetApp.getUi().showModalDialog(html, "Title") 函数一次,但没有再次调用 html 文件并创建一个无限循环,我似乎没有办法做到这一点。知道如何做到这一点吗?

【问题讨论】:

您可以使用无模式对话框,然后用户可以在对话框仍然打开时选择范围,然后返回并点击按钮让您知道它们已完成。 谢谢,是否有一两个链接可以说明如何在 GAS 中完成此操作?你能在网上推荐任何类似的例子吗?谢谢! This 是一个不那么简单的例子 感谢 Cooper,我仍然无法理解这是如何工作的。目前,如果用户从下拉列表中选择,有代码调用 HTML SpreadsheetApp.getUi().showModalDialog(html, "Statistics");那么,我是否只需将其更改为无模式对话框?我对事情的时间安排以及如何将所有这些工作到我的代码中感到有点困惑。你知道有什么方法可以在没有其他 HTML 代码的情况下调用函数 DrawChart() 吗?我不清楚无模式框是否有按钮,显示代码,对不起,对于那个例子来说不够先进。 我留下了一个更简单的例子。 【参考方案1】:

这是一个使用无模式对话框选择范围的简单示例。只需添加一些额外功能即可。

代码.gs:

function selRange()//run this to get everything started.  A dialog will be displayed that instructs you to select a range.

  var output=HtmlService.createHtmlOutputFromFile('pickRange').setWidth(300).setHeight(200).setTitle('Select A Range');
  SpreadsheetApp.getUi().showModelessDialog(output, 'Range Selector');


function selCurRng() 

  var sso=SpreadsheetApp.getActive();
  var sh0=sso.getActiveSheet();
  var rg0=sh0.getActiveRange();
  var rng0A1=rg0.getA1Notation();
  rg0.setBackground('#777700');
  return rng0A1;


function clrRange(range)

  var sso=SpreadsheetApp.getActive();
  var sh0=sso.getActiveSheet();
  var rg0=sh0.getRange(range);
  rg0.setBackground('#ffffff');

pickRange.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script>
     var grange='';
     function selectRange()
     
       $('#btn1').prop('disabled',true);
       $('#btn2').prop('disabled',false);
       google.script.run
         .withSuccessHandler(setResponse)
         .selCurRng();
     
     function setResponse(r)
     
       grange=r;
       var msg='You have select the range '  + r; 
       $('#instr').css('display','none');
       $('#rsp').text(msg); 
     
     function clearAndClose()
     
       google.script.run.clrRange(grange);
       google.script.host.close();

     
     console.log('My Code');
    </script>
  </head>
  <body>
    <div id="rsp"></div>
    <div id="instr">Please select your desired range.</div>
    <input type="button" id="btn1" value="Range Selected" onClick="selectRange();" />
    <br /><input type="button" id="btn2" value="close" onClick="clearAndClose();"; disabled="true" />
  </body>
</html>

【讨论】:

所以,如果我跟随,selRange() 会调用 HTML 并要求用户选择一个范围。然后,除了等待 selCurRng() 完成的 setResponse() 之外,HTML 中的所有函数都会运行。我仍然不太了解用户在哪里暂停或按钮如何充当“网关”,因为脚本进程没有更好的词。 SelectRange() 中的代码是否会暂停,直到单击按钮?我认为其余的都是有道理的。 关于 Cooper 按钮的另一个问题。我去了here,没有看到您用来创建“#btn1”和“#btn2”的语法。我没有找到任何可以显示它们如何相互作用的东西。感谢您的帮助! 当您单击其中一个按钮时,该过程由 onClick 事件指示,因此我实际上将 onClick 属性放在输入标记中。 Cooper 这里有几个问题。我试图稍微弄乱你的代码,所以我可以看看我是否可以用 Ui.Prompt 提示用户输入一个范围。我想对非连续范围这样做。我还想将这些数据作为数组传递,然后调用 ArrayToDataTable,如上所示。我没有成功地做到这一点,似乎一旦初始对话框消失,就没有办法让它回来(提示导致了这个)。有什么方法可以按照您所知道的方式进行吗?还是我将不得不尝试与此相结合的另一种方法? 我很确定目前在 Google Apps 脚本中不支持非连续范围。

以上是关于提示用户输入 .gs 函数中的范围,将数组传递给 html 脚本并重新关注 HTML 对话框的主要内容,如果未能解决你的问题,请参考以下文章

将struct数组传递给输入函数

从工作表将二维数组传递给 VBA/UDF 函数

如何将 A1:A500 等数组数据传递到 Excel 用户定义函数中

将二维字符串数组传递给函数时出错 (C++)

将 SQL 输入日期范围传递给 SHINY 中的查询

php array_map与array_walk使用对比