【GAS】Apps Scriptの中でURLをクリックして実行する方法|デプロイしたdoGetのスクリプトをボタンクリックで自動実行

Apps Script apps script GAS-prograshi(プロぐらし)-kv AppsScript
記事内に広告が含まれていることがあります。
[PR]

Google App Script(GAS)を使っているときに、スプレッドシートやフォームの編集権限のない人にプログラムを実行してもらって更新を行いたいときがあります。

そんなときはプログラムをデプロイしてURLをクリックすることでdoGetに設定したスクリプトを自動で実行することができます。

しかし、スプレッドシートに実行用のリンクを埋め込んでおくのも1つの手ですが、ボタンクリックでプログラムを発動させた方がオシャレという利点があります。

ここでは、GASでボタンクリックと同時にフォームやスプレッドシートの編集許可がない人がプログラムを実行する方法についてまとめています。


プログラムの概要

ここで作成するプログラムは以下のようなものです。

スプレッドシート上に設置した「フォーム更新ボタン」をクリックします。


クリックすると一瞬モーダルが立ち上がり自動でリダイレクトがかかってモーダルが消えます

すると新しいタブが立ち上がってスクリプトを実行し、完了してくれます。


プログラムを実行する人はボタンクリックするだけです。(あとは開かれたタブを閉じる)


全体の流れ

GASでボタンクリックと同時にフォームやスプレッドシートの編集許可がない人がプログラムを実行できるようにする手順は大まかに以下になります。

doGetを自動で実行する方法
  1. 実行する関数を作成する。
  2. doGetを設定する。
  3. デプロイして実行URLを発行する。
  4. ボタンクリックで発動する関数を作成する。


1の実行したい関数は、2のdoGet関数の中に記述しても問題ありません。ここではメンテや個別に実行したい用途もあるため別々で作成します。


コードの全体像

1. 実行する関数

まずは実行したいスクリプトを作成します。

ここでは、ボタンクリックと同時にスプレッドシートに記載してある内容で対象のフォームを更新するプログラムを設定しています。

このスクリプトは重要ではないので、適用に読み飛ばしてください。

function 実行する関数名() {

  const ssid = "スプシのID"
  
  const ss = SpreadsheetApp.openById(ssid);
  const sheet = ss.getSheetByName("シート名");

  let startRow = 21;
  let lastRow = sheet.getLastRow();
  let lastCol = sheet.getLastColumn();
  let values = sheet.getRange( startRow, 1, lastRow - startRow + 1, lastCol ).getValues();
  // console.log(values);

  let formEditUrlCol = 5;
  let formPubUrlCol = 6;
  let sheetConnectCol = 7;
  let eventSheetUrlCol = 8;
  let eventSsNameCol = 9;
  let formTitleCol = 15;
  let formStatusCol = 16;
  let formDescCol = 25;

  let openDateCol = 26;
  let closeDateCol = 27;
  let remainCol = 18;
  let forceCloseCol = 29;
  let sendMsgCol = 31;
  let closedMsgCol = 32;
  
  let msg = "";
  let now = new Date;
   
  values.forEach( (rowVals, index) => {
    // console.log(rowVals);
    
    //フォームURLがある場合のみ
    let formEditUrl = rowVals[formEditUrlCol - 1];
    if( !!formEditUrl ){
      let form = FormApp.openByUrl(formEditUrl);
      let formPubUrl = form.getPublishedUrl();
      let formTitle = rowVals[ formTitleCol -1 ];
      let formDesc = rowVals[ formDescCol - 1 ];
      let sendMsg = rowVals[ sendMsgCol -1 ];
      let closedMsg = rowVals[ closedMsgCol -1 ];
      let formStatus = form.isAcceptingResponses();
      let sheetConnection = rowVals[ sheetConnectCol - 1 ];
      // console.log("公開URL:", formPubUrl, "ステータス:", formStatus);

      //シート連携が未実施の場合のみデータ更新
      if( !sheetConnection ){
        //PublishedURLをセット
        sheet.getRange( startRow + index, formPubUrlCol ).setValue( formPubUrl );

        //シート名をセット
        let eventSheetUrl = rowVals[ eventSheetUrlCol - 1 ];
        let eventSs = SpreadsheetApp.openByUrl( eventSheetUrl );
        let eventSsName = eventSs.getName();
        sheet.getRange( startRow + index, eventSsNameCol ).setValue( eventSsName );

        //フォームの回答先にスプシを指定
        
        let eventSsId = eventSs.getId();
        form.setDestination(FormApp.DestinationType.SPREADSHEET, eventSsId);

        sheet.getRange( startRow + index, sheetConnectCol ).setValue( true );
      }

      //受付状況を更新
      let remain = rowVals[remainCol - 1];
      let openDate = rowVals[openDateCol - 1];
      let closeDate = rowVals[closeDateCol - 1];
      let forceClose = rowVals[forceCloseCol - 1];
      let judge;
      // console.log("残人数:", remain, "開始日:", openDate, "終了日:", closeDate, "強制終了:",forceClose);

      if( forceClose || remain <= 0 || now < openDate || now >= closeDate ){
        //受付終了時の処理
        judge = false;

        //ステータス更新
        if( formStatus != judge ){
          form.setAcceptingResponses( judge );
          sheet.getRange( startRow + index, formStatusCol ).setValue("受付終了")
          msg +=  "・" + formTitle + ":受付を「終了」しました。\n";
        }


        //受付終了中のメッセージを変更
        if( closedMsg != form.getCustomClosedFormMessage() ){
          form.setCustomClosedFormMessage( closedMsg );
          msg +=  "・" + formTitle + ":「受付終了時のメッセージ」を変更しました。\n";
        }
        
      }else{
        //受付中の処理
        judge = true;

        //ステータス更新
        if( formStatus != judge ){
          form.setAcceptingResponses( judge );
          sheet.getRange( startRow + index, formStatusCol ).setValue("受付中")
          msg +=  "・" + formTitle + ":「受付中」にしました。\n";
        }

        //イベント名を変更
        if( formTitle != form.getTitle() ){
          form.setTitle( formTitle );
          msg +=  "・" + formTitle + ":「タイトル」を変更しました。\n";
        }

        //説明を変更
        if( formDesc != form.getDescription() ){
          form.setDescription( formDesc );
          msg +=  "・" + formTitle + ":「説明」を変更しました。\n";
        }

        //送信後のメッセージを変更
        if( sendMsg != form.getConfirmationMessage() ){
          form.setConfirmationMessage( sendMsg );
          msg +=  "・" + formTitle + ":「送信後の表示メッセージ」を変更しました。\n";
        }
      }  
    }
  })


  //表示するメッセージ
  if( msg == "" ){
    msg = "変更はありません。";
  }

  return msg;
}


Point

doGetで実行する関数の1番重要なポイントは最後に「return」で文字列を返していることです。

これで、doGetのプログラム実行後にブラウザに戻り値で指定した文字列を表示します。


doGetの設定

GASにはdoGetという特別な関数があります。

doGetはデプロイしたプログラム実行URLをクリックしたときに自動で実行される関数です。

function doGet() {
  let res = 実行する関数名();

  let msg = "プログラムを実行しました。\n\n" + res + "\n\n"
            + "タブを閉じてください。";
  
  return ContentService.createTextOutput(msg);
}


URLクリックでdoGet関数が実行されると、指定した「実行する関数名」のプログラムを実行し、戻り値を変数「res」に格納します。

戻り値と「プログラムを実行しました」というも字列を「msg」という変数に格納します。

最後にContentService.createTextOutputを使うことで、ブラウザ上に変数の内容を表示します。

Point


doGetの中でreturn ContentService.createTextOutput(文字列);を記述すると、プログラム実行完了後に、引数に指定した内容をブラウザ上に表示します。

return ContentService.createTextOutput(文字列);



デプロイして実行URLを発行する

doGetの関数の作成が完了したら、doGetを実行するためのプログラム実行URLを発行します。

Apps Script右上の「デプロイ」ボタンをクリックします。

「新しいデプロイ」をクリックします。



デプロイが初回の場合は左上の歯車アイコンををクリックして「ウェブアプリ」を選択します。


次に、デプロイの詳細を入力する画面が表示されます。以下のように設定してください。

デプロイの設定
  • 説明:任意です。何も指定しないと「無題」となります。
  • ウェブアプリ: 「自分」を選択
  • アクセスできるユーザー: Googleアカウントを持つ全員 or 全員


特に重要なのが「ウェブアプリ(次のユーザーとして実行)」です。今回doGetを作成している目的は、スクリプトを実行したときに編集権限を持たない人でもプログラムを実行できるようにするためです。

ここで「自分(自分のgmailアドレス)」を選択しておくことで、URLがクリックされたときに、誰がクリックしても自分としてプログラムを実行することができます


設定が完了したら「デプロイ」をクリックします。

デプロイするとウェブアプリのURLが発行されるのでこれをコピーします。(※デプロイIDではありません)


このURLをブラウザで開けば、doGetが実行されるようになります。

doGetの注意点

デプロイしたURLをクリックしたときに実行されるdoGet関数およびdoGetの中で呼び出している関数などのプログラムは、デプロイした時点のものになります。

コードを変更した場合は再度デプロイを行い、新しいURLを発行してください。

※ただし、呼び出しているHTMLはデプロイ状態によらず最新のものが反映されます。


ボタンクリックで発動する関数を作成する

最後にボタンクリックで発動する関数を作成します。

function showModal() {
  let url = "ウェブアプリのURL";

  let innerHtml = `
    <html>
    
      <script>
          window.close = function(){
            window.setTimeout(function(){
              google.script.host.close()
            },9)
          };

          var a = document.createElement("a"); a.href="${url}";
          a.target="_blank";
          
          if(document.createEvent){

            var event=document.createEvent("MouseEvents");
            if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){
              window.document.body.append(a)
            }

            event.initEvent("click",true,true); a.dispatchEvent(event);
          }else{
            a.click()
          }
          close();

        google.script.host.setHeight(40);
        google.script.host.setWidth(410)
      </script>

    </html>`

    html = HtmlService.createHtmlOutput(innerHtml).setWidth( 120 ).setHeight( 1 );
    SpreadsheetApp.getUi().showModalDialog( html, "フォーム更新" );  
}


この関数名はshowModalとしています。

コードの作成が完了したら、ボタンに関数をセットすれば完了です。

ボタンをクリックして「スクリプトを割り当て」を選択します。


スクリプト名を入力して「確定」をクリックすれば完了です。


注意点

プログラムを実行するとブラウザによっては新しいタブを自動で開くことをブロックします。

その場合は「ポップアップをブロック」をクリックして、解除する必要があります。


手動でリンククリックにする方法

上記のコードはJavaScriptを使って自動でリンクをクリックして新しいタブを開いています。

もし、これを自動ではなく、手動でリンクテキストをクリックする形にしたい場合は以下のように書き換えてください。

function showModal() {
  let url = "https://script.google.com/macros/s/AKfycbz4HO9LbxWePWua31dmcbPhvHtCAH6yJJ9OvoFYmHPwd_I8O1MWUc8VLnma51OqjZXj_w/exec";

  let innerHtml = `
    <html>
      <!--
      <script>
          window.close = function(){
            window.setTimeout(function(){
              google.script.host.close()
            },9)
          };

          var a = document.createElement("a"); a.href="${url}";
          a.target="_blank";
          
          if(document.createEvent){

            var event=document.createEvent("MouseEvents");
            if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){
              window.document.body.append(a)
            }

            event.initEvent("click",true,true); a.dispatchEvent(event);
          }else{
            a.click()
          }
          close();
      </script>
      -->

      <body style="word-break:break-word;font-family:sans-serif;">
        <a href="${url}" target="_blank" onclick="window.close()">ここをクリックしてください。</a>
      </body>
                    
      <script>
        google.script.host.setHeight(40);
        google.script.host.setWidth(410)
      </script>

    </html>`

    html = HtmlService.createHtmlOutput(innerHtml).setWidth( 120 ).setHeight( 1 );
    SpreadsheetApp.getUi().showModalDialog( html, "フォーム更新" );  
}


実行すると、モーダルの中にリンクテキストが現れ、クリックすればdoGetのプログラムを実行するようになります。

タイトルとURLをコピーしました