Google Scripts电子表格脚本:for循环中的函数在循环完成之前未完全执行

时间:2014-05-06 01:14:55

标签: javascript for-loop google-apps-script google-sheets do-while

我正在编写一个用于谷歌电子表格的脚本。我希望脚本循环显示URL的电子表格。当它循环时,该函数应调用一个UI实例,该UI实例显示url链接并接收有关url为'current'或'expired'的用户输入,并将其标记为电子表格。

理想情况下,在用户选择一个选项后,单击“下一步”按钮,该URL的对话框将关闭,下一个URL的对话框将打开。

代码如下。

   function getUrlsToCheck(){

   /**
   * Asks user to input range of urls to check.
   */

   var spreadsheet = SpreadsheetApp.getActive();
   var sheet = spreadsheet.getSheets()[0];

  // Prompt the user for the range with the starting row and ending row.
   var rowStart = Browser.inputBox('Starting Entry',
      'Please enter the starting row of the urls you want to check' +
      ' (for example, "1"):',
      Browser.Buttons.OK_CANCEL);
    if (rowStart == 'cancel') {
    return;
  }

    var rowNumber1 = Number(rowStart);
       if (isNaN(rowNumber1) || rowNumber1 < 2 ||
        rowNumber1 > spreadsheet.getLastRow()) {
        Browser.msgBox('Error',
        Utilities.formatString('Row "%s" is not a valid starting point.', rowStart),
        Browser.Buttons.OK);
    return; 
  }

   var rowEnd = Browser.inputBox('Ending Entry',
      'Please enter the ending row of the urls you want to check' +
       ' (for example, "56"):',
       Browser.Buttons.OK_CANCEL);
    if (rowEnd == 'cancel') {
    return;
  }

    var rowNumber2 = Number(rowEnd);
    if (isNaN(rowNumber2) || rowNumber2 < rowNumber1 || rowNumber1 == rowNumber2) {
        Browser.msgBox('Error',
        Utilities.formatString('Row "%s" is not a valid ending point.', rowEnd),
        Browser.Buttons.OK);
    return; 
}

    var numOfRowsToCheck = (rowNumber2 - rowNumber1);
    var range = sheet.getRange(rowNumber1, 1, (numOfRowsToCheck + 1), 1);
    var data = range.getValues();

  /*
   *Loop to retrieve URLs and show a link in the Ui instance
   */

    for(var i = 0; i < data.length; i++) {

    var activeRow = (Number(i) + rowNumber1);

    var range4 = sheet.getRange(activeRow, 4);
    var range5 = sheet.getRange(activeRow, 5);

    var app = UiApp.createApplication().setHeight(150).setWidth(250);
    app.setTitle("Check URL");

    var link1 = app.createAnchor('Check', data[i]);
    var panel = app.createVerticalPanel();

    var infoLabel = app.createLabel(Utilities.formatString('Check the link for entry %s', activeRow)).setId('infoLabel');
    var infoLabel1 = app.createLabel('').setId('infoLabel1');

    var current = app.createRadioButton("group", "Current").setName('current').setId('current');
    var expired = app.createRadioButton("group", "Expired").setName('expired').setId('expired');

    var hidden = app.createHidden("yourObject", Utilities.jsonStringify(activeRow));

    var handler = app.createServerChangeHandler('current');
    handler.addCallbackElement(panel).addCallbackElement(hidden);
    current.addClickHandler(handler);

    var handler2 = app.createServerChangeHandler('expired');
    handler2.addCallbackElement(panel).addCallbackElement(hidden); 
    expired.addClickHandler(handler2);

    var next = app.createButton('Next').setId('next');
    var handler3 = app.createServerHandler('next');
    handler3.addCallbackElement(panel);
    next.addClickHandler(handler3);

    panel.setSpacing(5);

    panel.add(infoLabel);
    panel.add(link1);
    panel.add(current);      
    panel.add(expired);
    panel.add(infoLabel1);
    panel.add(next);

    app.add(panel);

    spreadsheet.show(app);  
   }     
  }

     function next(e){
     var app = UiApp.getActiveApplication(); 
     app.close();

   return app;
  }

function current(e){
  var app = UiApp.getActiveApplication(); 
  app.getElementById('expired').setValue(false);

  var yourObj = Utilities.jsonParse(e.parameter.yourObject);

  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getSheets()[0];
  var range4 = sheet.getRange(yourObj, 4);
  var range5 = sheet.getRange(yourObj, 5);

  range4.setValue('x');
  range5.setValue('');

  app.getElementById('infoLabel1').setText('This link has been marked current');

  return app;
 }

function expired(e){
  var app = UiApp.getActiveApplication(); 
  app.getElementById('current').setValue(false);

  var yourObj = Utilities.jsonParse(e.parameter.yourObject);

  var spreadsheet = SpreadsheetApp.getActive();
  var sheet = spreadsheet.getSheets()[0];
  var range4 = sheet.getRange(yourObj, 4);
  var range5 = sheet.getRange(yourObj, 5);

  range4.setValue('');
  range5.setValue('x');

 app.getElementById('infoLabel1').setText('This link has been marked expired'); 

  return app;
 }

我遇到的问题是循环循环,没有足够的时间来接受加载用户信息的对话框;所以你只能看到最后一个网址的对话框。

我尝试了几件事,因为他们没有工作,我必须做错了。

  • 我尝试插入系统暂停。

  • 我也试过让函数成为生成函数,但是 yield命令没有正确编译。

  • 我也尝试过使用do while循环而不是for循环。该
    条件是否与下一个按钮是否相关 禁用。

关于如何在循环结束前让函数的每一步都执行的任何建议?

1 个答案:

答案 0 :(得分:1)

此代码的问题在于,它会同时创建所有对话框,但只有在完成第一个对话框后才能创建对话框。重写很多东西可能会更好,但是对于这个演示,我只是将你的代码转换为能够同步运行。

因此,您不必在for中的getUrlsToCheck循环中,而是在回调处理程序next中创建对话框。这确实意味着我们必须基本上做出recursive call种类。我们还必须跟踪i并传递它。为了使对代码的编辑最小化,我将getUrlsToCheck中的大部分代码移出到一个函数,该函数从参数irowNumber1rowNumber2初始化所需的数据,打开对话框。

我还在verify中添加了一些代码,用于将数据i+1rowNumber1rowNumber传递给next处理程序。在next中,我们使用传递的处理程序的已解析JSON调用verify

最后,为了开始循环,我们通过verifygetUrlsToCheckrowNumber1传递rowNumber2中的i=0

所以代码看起来像

function getUrlsToCheck() {
    /**
     * Asks user to input range of urls to check.
     */

    var spreadsheet = SpreadsheetApp.getActive();
    var sheet = spreadsheet.getSheets()[0];

    // Prompt the user for the range with the starting row and ending row.
    var rowStart = Browser.inputBox('Starting Entry',
        'Please enter the starting row of the urls you want to check' +
        ' (for example, "1"):',
        Browser.Buttons.OK_CANCEL);
    if (rowStart == 'cancel') {
        return;
    }

    var rowNumber1 = Number(rowStart);
    if (isNaN(rowNumber1) || rowNumber1 < 2 ||
        rowNumber1 > spreadsheet.getLastRow()) {
        Browser.msgBox('Error',
            Utilities.formatString('Row "%s" is not a valid starting point.', rowStart),
            Browser.Buttons.OK);
        return;
    }

    var rowEnd = Browser.inputBox('Ending Entry',
        'Please enter the ending row of the urls you want to check' +
        ' (for example, "56"):',
        Browser.Buttons.OK_CANCEL);
    if (rowEnd == 'cancel') {
        return;
    }

    var rowNumber2 = Number(rowEnd);
    if (isNaN(rowNumber2) || rowNumber2 < rowNumber1 || rowNumber1 == rowNumber2) {
        Browser.msgBox('Error',
            Utilities.formatString('Row "%s" is not a valid ending point.', rowEnd),
            Browser.Buttons.OK);
        return;
    }

    var numOfRowsToCheck = (rowNumber2 - rowNumber1);


    /*
     *Moved everything to function verify();
     */
    verify({
        i: 0,
        rowNumber1: rowNumber1,
        rowNumber2: rowNumber2
    })
}

function verify(myObj) {
    //gets variable from passed json obj
    var i = myObj.i 
    var rowNumber1 = myObj.rowNumber1
    var rowNumber2 = myObj.rowNumber2

    //mostly the same
    var activeRow = (Number(i) + rowNumber1);

    var spreadsheet = SpreadsheetApp.getActive();
    var sheet = spreadsheet.getSheets()[0];
    var numOfRowsToCheck = (rowNumber2 - rowNumber1);
    var range = sheet.getRange(rowNumber1, 1, (numOfRowsToCheck + 1), 1);
    var data = range.getValues();
    var range4 = sheet.getRange(activeRow, 4);
    var range5 = sheet.getRange(activeRow, 5);

    if (i < data.length) {

        var app = UiApp.createApplication().setHeight(150).setWidth(250);
        app.setTitle("Check URL");

        var link1 = app.createAnchor('Check', data[i]);
        var panel = app.createVerticalPanel();

        var infoLabel = app.createLabel(Utilities.formatString('Check the link for entry %s', activeRow)).setId('infoLabel');
        var infoLabel1 = app.createLabel('').setId('infoLabel1');

        var current = app.createRadioButton("group", "Current").setName('current').setId('current');
        var expired = app.createRadioButton("group", "Expired").setName('expired').setId('expired');

        var hidden = app.createHidden("yourObject", Utilities.jsonStringify(activeRow));

        var handler = app.createServerChangeHandler('current');
        handler.addCallbackElement(panel).addCallbackElement(hidden);
        current.addClickHandler(handler);

        var handler2 = app.createServerChangeHandler('expired');
        handler2.addCallbackElement(panel).addCallbackElement(hidden);
        expired.addClickHandler(handler2);

        //added this to pass state to next()
        var hidden = app.createHidden("yourObject", Utilities.jsonStringify({
            i: i + 1, //increment i
            rowNumber1: rowNumber1,
            rowNumber2: rowNumber2
        }));

        var next = app.createButton('Next').setId('next');
        var handler3 = app.createServerHandler('next');
        handler3.addCallbackElement(panel);
        handler3.addCallbackElement(panel).addCallbackElement(hidden);
        next.addClickHandler(handler3);

        panel.setSpacing(5);

        panel.add(infoLabel);
        panel.add(link1);
        panel.add(current);
        panel.add(expired);
        panel.add(infoLabel1);
        panel.add(next);

        app.add(panel);

        spreadsheet.show(app);
    }
}


function next(e) {
    var app = UiApp.getActiveApplication();
    app.close();

    //parse string to json and call verify to open next dialog
    verify(Utilities.jsonParse(e.parameter.yourObject));

    return app;
}

function current(e) {
    var app = UiApp.getActiveApplication();
    app.getElementById('expired').setValue(false);

    var yourObj = Utilities.jsonParse(e.parameter.yourObject);

    var spreadsheet = SpreadsheetApp.getActive();
    var sheet = spreadsheet.getSheets()[0];
    var range4 = sheet.getRange(yourObj, 4);
    var range5 = sheet.getRange(yourObj, 5);

    range4.setValue('x');
    range5.setValue('');

    app.getElementById('infoLabel1').setText('This link has been marked current');

    return app;
}

function expired(e) {
    var app = UiApp.getActiveApplication();
    app.getElementById('current').setValue(false);

    var yourObj = Utilities.jsonParse(e.parameter.yourObject);

    var spreadsheet = SpreadsheetApp.getActive();
    var sheet = spreadsheet.getSheets()[0];
    var range4 = sheet.getRange(yourObj, 4);
    var range5 = sheet.getRange(yourObj, 5);

    range4.setValue('');
    range5.setValue('x');

    app.getElementById('infoLabel1').setText('This link has been marked expired');

    return app;
}

我们可能会做得更好,但这可以用于测试。