クライアント スクリプティング

クライアント スクリプトは、ユーザーのパソコン上でブラウザの JavaScript ランタイムによって実行されます。UI イベントを処理する場合や、DOM 要素とウィジェットのプロパティを変更する場合に最適です。

クライアント スクリプトで App Maker API を使用し、サーバーとのやり取りをトリガーすることもできます。たとえば、クライアント スクリプトでデータベースからデータを取得して変更できます。また、サーバー スクリプトを呼び出すこともできます。

非同期操作とコールバック関数

アプリのユーザー インターフェース(UI)の応答性を維持するため、App Maker ではクライアント スクリプトを非同期で実行できます。ブラウザアプリによっては、外部リソースの処理待ち状態になると、アプリ全体が待機状態になる場合があります。この場合、UI も待機し、応答しなくなります。

非同期コードの場合、UI やその他のアプリの操作は応答可能な状態を維持しますが、スクリプトが記述された順序で実行されない可能性があります。操作の結果を処理する場合など、非同期操作の終了後にスクリプトを実行するには、コールバック関数を使用します。

コールバック関数は、操作の完了時に実行されるクライアント スクリプトです。操作に成功したときに実行される関数を指定することも、成功と失敗で異なる関数を実行するオブジェクトを指定することもできます。

成功専用のコールバック関数

成功専用のコールバック関数を使用すると、操作が成功した場合にのみコールバック関数が実行されます。操作が失敗した場合は、何も実行されません。簡単な例を見てみましょう。次のコードでは、createItem() で非同期にレコードを作成し、それに関する警告を表示します。

widget.datasource.createItem(function (record) {
  alert('Record with ID ' + record.id + ' was created in the database.');
});

成功 / 失敗のコールバック関数

前の例を拡張したものです。このメソッドを使用して失敗を通知し、エラー報告、クリーンアップまたはロールバックを行います。

widget.datasource.createItem({
  success: function (record) {
    alert('Record with ID ' + record.id + ' was created in the database.');  // executes if record was created
  },
  failure: function (error) {
    console.info("No new record for you!"); // executes if record wasn't created
  }
});

コールバック関数を使用しない場合

コールバックを省略するか、コールバックとして null を渡すと、オペレーションの終了を待たずにコードが続行します。例:

    widget.datasource.createItem();
    console.info("warning, record is probably not yet created!");

トラブルシューティング

クライアント スクリプトをトラブルシューティングしてエラーを修正する場合のヒントをいくつか紹介します。

  • スクリプト エディタで構文エラーを探す。 App Maker スクリプト エディタでは、構文上の問題が自動的に警告されます。スクリプトの行番号の左側にある警告ラベルを確認してください。括弧の付け忘れなど、一般的なエラーが警告されます。

  • ブラウザの JavaScript コンソールでランタイム エラーを探す。 アプリのプレビュー インスタンスまたはデプロイ済みのバージョンを開き、ブラウザの JavaScript コンソールを開きます。Chrome では、Ctrl+Shift+j または Alt-Cmd-j で JavaScript コンソールを開きます。よくあるランタイム例外は、null による参照解除やキャッチされない throw ステートメントです。スクリプトに debugger; ステートメントを追加すると、スクリプトの実行を停止し、問題のある領域を特定できます。debugger; を有効にするには、DevTools は開いておく必要があります。デバッグの詳細については、Chrome DevTools で JavaScript のデバッグを開始するをご覧ください。

  • ログと警告を有効にして、スクリプトの実行を追跡する。 ブラウザの組み込み console.log() 関数を使用すると、ログを JavaScript コンソールに送信できます。また、alert() を使用して、スクリプトの実行を中断する警告ボックスを開くこともできます。このボックスを閉じるまでスクリプトは実行されません。

クライアント スクリプトの例

バインディング式でスクリプトを使用する

JavaScript を使用して、バインディング式で計算を行うことができます。たとえば、ボタンの enabled プロパティの次の式では、Name フィールドが空白の場合、あるいは Age フィールドの値が 18 未満の場合、ボタンを無効にします。

(@widget.parent.children.NameTextBox.value).length != 0 &&
@widget.parent.children.AgeTextBox.value >= 18

まず、App Maker パーサーが @ で始まるバインディング式を解決し、NameAge の値を探します。その後、これらの値を式で置き換え、残りの JavaScript を評価します。

1 行目の括弧は結合式の終わりを表します。これがない場合、App Maker は value プロパティではなく、length プロパティの変更を監視します。

サーバー スクリプトを呼び出す

App Maker API を使用すると、クライアント スクリプトからサーバー スクリプトを呼び出すことができます。サーバー スクリプトの呼び出しは非同期のため、スクリプトの結果を処理するにはコールバックを使用する必要があります。

次のクライアント スクリプトは、サーバー スクリプトを呼び出して現在の Google の株価を取得し、その結果をコールバックを使用してアラート メッセージとして表示します。

クライアント スクリプト:

function getGoog() {
  google.script.run.withSuccessHandler(function(result) {
    var quote = result.trim().split("\n").pop().split(",").pop();
    alert(quote);
  }).getGoogleStockInfo();
}

サーバー スクリプト:

function getGoogleStockInfo() {
  var url = "https://www.google.com/finance/getprices?f=d,c&q=GOOG";
  var response = UrlFetchApp.fetch(url);
  return response.getContentText();
}

外部スクリプトを動的に読み込む

外部の JavaScript ライブラリと同期してサードパーティ スクリプトを読み込むことができますが、もう少し作業が必要なものもあります。Google API クライアント ライブラリのように、コールバック パラメータを必要とするライブラリは、スクリプトに Settings > General > onAppStart を追加して動的に読み込む必要があります。

次のスクリプトは Google+ ライブラリを読み込みます。

// Suspends app loading until after the Google Client API loads.
loader.suspendLoad();
// Defines a callback function, for the client API. It must be global,
// so it's explicitly attached to the window object.
window.OnGapiClientLoad = function() {
  // Uses the Google Client API to load the Google+ library.
  gapi.client.load("plus", "v1", function() {
    // Continues loading the app once Google+ loads.
    loader.resumeLoad();
  });
};

var script = document.createElement("script");
script.setAttribute("type", "text/javascript");

// Specifies the name of the callback function in the "onload"
// parameter of the URL.
var url = "https://apis.google.com/js/client.js?onload=OnGapiClientLoad";
script.setAttribute("src", url);

document.getElementsByTagName("head")[0].appendChild(script);

Google API を呼び出す

最後の例はもう少し複雑で、実際の App Maker スクリプトに近いものになります。この例では、Google JavaScript API を使用します。

このスクリプトは、ページに Google マップを表示し、ユーザーの入力に基づいてページを更新します。このスクリプトは、次のウィジェットを含む Map というページで動作します。

  • StreetZip という名前の 2 つのテキスト フィールド。
  • MapDiv という名前の 200x200 の HtmlArea。loadMaps() を呼び出す onAttach イベントがあります。
  • updateMap() を呼び出す onClick() ハンドラを使用するボタン

スクリプト:

var map;
var geocoder;
var marker;

// Called by loadMaps() to set up widgets.
function createMap() {
  var div = app.pages.Map.descendants.MapDiv.getElement();
  map = new google.maps.Map(div, {
    center: new google.maps.LatLng(-34.397, 150.644),
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    zoom: 10,
  });
  geocoder = new google.maps.Geocoder();
  marker = new google.maps.Marker({map: map});
}

// Returns an address string from Street and Zip text fields.
function getAddress() {
  var page = app.pages.Map;
  var street = page.descendants.Street.value;
  var zip = page.descendants.Zip.value;
  return street + ", " + zip;
}

// Positions the map at the given location coordinates.
function showLocation(locations, status) {
  if (locations.length > 0) {
    var latLng = locations[0].geometry.location;
    map.panTo(latLng);
    marker.setPosition(latLng);
  }
}

// Sets up the Google Maps library.
function loadMaps() {
  google.load("maps", "3", {callback: createMap});
}

function updateMap() {
  geocoder.geocode({address: getAddress()}, showLocation);
}

スクリプトの概要:

  • MapDiv は、onAttach() ハンドラを使用して Google Maps API を設定します。
  • このスクリプトは、getAddress() を使用して Street フィールドと Zip フィールドからデータを取得し、ユーザー入力にアクセスします。