スクリプティングの概要

App Maker を使用すると、コーディングなしで比較的複雑なアプリケーションを作成できますが、ウィジェットやモデルエディタだけでは実装できない機能が必要になることがあります。App Maker の JavaScript スクリプト エディタを使用すると、このような機能を作成できます。

App Maker には、ユーザーのブラウザ上で実行されるクライアント スクリプトと、App Maker サーバー上で実行されるサーバー スクリプトがあります。App Maker のスクリプトを使用すると、次のような処理を行うことができます。

  • アプリ固有のロジックと計算を実行する
  • 外部のウェブサービスに接続する
  • カスタム権限チェックを作成する
  • その他...

クライアント スクリプトとサーバー スクリプト

クライアント スクリプトとサーバー スクリプトは、どちらも JavaScript を実行しますが、使用される場所や機能に違いがあります。

クライアント スクリプトの概要

  • クライアント スクリプトはユーザーのブラウザで実行されます。 DOM、ブラウザのローカル ストレージなどにアクセスできます。
  • クライアント スクリプトでウィジェットのプロパティを編集できます。 App Maker はウィジェットを JavaScript オブジェクトとして公開します。これらの外観、イベント、その他のプロパティをプログラムで変更できます。
  • クライアント スクリプトはブラウザをブロックします。 アプリの応答性を維持するため、クライアント スクリプトで複雑な計算は行わないでください。

  • クライアント API は非同期です。 クライアント スクリプトの呼び出しが順不同で実行される場合があります。詳細については、下記のデータモデルの使用例をご覧ください。

  • クライアント スクリプトは安全ではありません。 上級ユーザーであれば、ブラウザツールを使用してクライアント スクリプトの表示や変更を行うことができます。データのセキュリティや一貫性を維持するため、クライアント スクリプトに依存しないでください。

サーバー スクリプトの概要

  • サーバー スクリプトは Apps Script で実行されます。 データベースに直接アクセスして、カレンダー、メールなどの Apps Script API を使用できます。
  • サーバー スクリプトはリクエスト間で状態を保持しません。 これらは分散サーバー上で実行されるため、スクリプトを呼び出すたびにグローバル変数が空になります。
  • サーバー スクリプトに割り当てが適用される場合があります。 Apps Script サービスに対する呼び出しは、1 日の割り当てによって制限されています。
  • サーバー スクリプトは保護できます。 クライアント スクリプトとは異なり、機密データへのアクセスを制御するサーバー スクリプトを保護できます。監査やデータの整合性の維持に使用できます。

スクリプトの例

コードのサンプルを見ると、クライアント スクリプトとサーバー スクリプトの違いがよくわかります。以下では、To-Do リストアプリで使用されているスクリプトについて説明します。このアプリでは、ユーザーが複数の To-Do リストを作成し、それぞれのリストに複数の項目を追加できます。

クライアント: ページとウィジェットを操作する

次の onClick スクリプトは DeleteTodoListButton で使用されています。このスクリプトは、ユーザーがボタンをクリックしたときに確認ページに切り替えます。

    app.showPage(app.pages.DeleteTodoListConfirmationView);
    

クライアント: プロパティ バインディングを実装する

次のスクリプトは、DeleteTodoListButtonenabled プロパティに対するバインディング式です。ユーザーが空のタスクリストだけを削除するように、リストに項目がない場合にのみボタンを有効にします。

    @datasource.item != null && @datasource.item.TodoItems.length == 0
    

クライアントとサーバー: データモデルを操作する

クライアント:

次のスクリプトでは、新しい To-Do リストを作成して選択します。まず、サーバー スクリプトを呼び出して新しいリストレコードを作成し、次に TodoList モデルを再度読み込み、新しく作成されたリストを選択します。

    function onCreateTodoListClick() {
      var datasource = app.datasources.TodoList;
      google.script.run.withSuccessHandler(function(newKey) {

        // When created, redisplay todo lists.
        datasource.load(function() {

          // When reloaded, select new todo list.
          datasource.selectKey(newKey);
        });
      }).createTodoListWithItem();
    }
    

コードが上の処理順序と異なる場合があります。このスクリプトは、多くのクライアント スクリプトと同様に非同期的で実行されます。createTodoListWithItem() を実行してから load() を実行することはできません。どちらも非同期であるため、データソースが再度読み込まれる前に、新しい To-Do が作成される保証はありません。

代わりに、createTodoListWithItem() は、To-Do リストの項目が正常に作成された後にのみ実行されるコールバックと一緒に load() を呼び出します。非同期スクリプトとコールバックの詳細については、クライアント スクリプトをご覧ください。

サーバー:

次のサーバー スクリプトは createTodoListWithItem() で、上記のクライアント スクリプトから呼び出されます。アプリのデータベースにアクセスして、新しい To-Do リストとその項目を作成し、リストの Key を返します。

    function createTodoListWithItem() {
      // Automatically number todo lists for the user.
      var lock = LockService.getScriptLock();
      lock.waitLock(10000);
      var query = app.models.TodoList.newQuery();
      var allTodoLists = query.run();
      var todoList = app.models.TodoList.newRecord();
      var newListNumber = allTodoLists.length + 1;
      todoList.name = "My list " + newListNumber;
      app.saveRecords([todoList]);
      lock.releaseLock();

      // Create first todo item for user convenience.
      var todoItem = app.models.TodoItem.newRecord();
      todoItem.TodoList = todoList;
      app.saveRecords([todoItem]);
      return todoList._key;
    }
    

サーバー スクリプトはデータを自動的に保存しないため、このスクリプトでは saveRecords() を呼び出して、モデルに対する変更を保存します。レコードを作成または編集する独自のスクリプトを作成する場合にも、この点を忘れないでください。

このスクリプトは、データの一貫性を維持するためにロックも使用します。ロックの詳細については、サーバー スクリプトをご覧ください。

サーバー: セキュリティ、監査、データの整合性を維持する

サーバー スクリプトを使用すると、データの一貫性と安全性を維持できます。上記のスクリプトは、ロックサービスを使用して、クエリと作成操作のアトミック性を実現しました。

特定のモデルイベントを許可しないように例外を使用して、カスタム権限を実装することもできます。たとえば、モデルの onDelete() イベントに次のコードを追加すると、レコードが削除されなくなります。

    throw "Deletions now allowed";
    

onCreate() ハンドラを使用して、監査を作成することもできます。

    var email = Session.getActiveUser().getEmail();
    record.setAudit("Created on " + new Date() + " by user " + email + "\n");
    

クライアントとサーバー: 他の URL からデータを取得する

クライアント:

XMLHttpRequest または App Maker の HtmlArea ウィジェットを使用して、IFRAME を挿入します。

サーバー:

Apps Script の URL 取得サービスを使用します。

クライアント: カスタム JavaScript ライブラリを統合する

外部の JavaScript ライブラリを読み込む方法は 2 つあります。

スクリプト検証用の JSHint

App Maker では、いくつかの JSHint ディレクティブがサポートされています。たとえば、ignore ディレクティブを使用すると、コードブロックの静的チェッカーを無効にできます。

/* jshint unused: true, eqnull: false */
    var w = 3;   // Warning: w is defined but never used.
    alert(10 == null); // Warning: use '===' to compare with 'null'.

    /* jshint ignore:start */
    var y = 4;     // No warning.
    alert(10 == null); //  No warning.
    /* jshint ignore:end */

    var a = 5;   // Warning: a is defined but never used.
    alert(10 == null); // Warning: use '===' to compare with 'null'.
    

JSHint の詳細については、JSHint のドキュメントをご覧ください。