メインコンテンツまでスキップ

10. ロジック & スクリプティング

基本構造を理解する

  • スクリプトは純粋なJavaScript(ES6+)です → 標準的な言語機能はすべて期待どおりに動作します:
    • 条件分岐(if/else、switch)
    • ループ(for、while)
    • 三項演算子
    • 配列とオブジェクト
    • JSON.parse、JSON.stringify
    • 標準的な文字列操作と数値演算
  • ページのライフサイクルは、ライフサイクルイベントを通じて管理します。グローバルオブジェクトを使うと、データやナビゲーション、アニメーションを管理できます。ウィジェットオブジェクトを使うと、ウィジェットのプロパティを操作して見た目を細かく制御したり、他のウィジェットに対するユーザー操作に応じて見た目や動作を変更したりできます。これらを組み合わせることで、ページに命を吹き込めます。

ライフサイクルイベント

  • 画面は、作成・使用・終了の各タイミングでLucyが自動的に呼び出すコールバックに沿って動作します。
関数タイミングと役割
onStart(arg)画面の開始時に最初に呼び出されます。ここでデータの初期化やイベントのバインドを行います。
onClose()画面が閉じられるときに呼び出されます。リソースを解放し、後処理を行います。
onReceiveDone()データの受信が正常に完了したときに呼び出されます。受信したデータでUIを更新します。
onReceiveError()データの受信に失敗したときに呼び出されます。ネットワーク障害などのエラーを処理します。

ライフサイクルイベントの全一覧と各イベントの詳しい説明は、11. Script APIドキュメントのLifeCycle Eventsセクションを参照してください。

グローバルオブジェクト

  • グローバルオブジェクトは、Lucy Studioがあらかじめ用意しているオブジェクトです。importや手動セットアップは不要で、アプリ全体で共有され、常に利用できます。
グローバルオブジェクト制御対象
$appアプリ全体の操作: ナビゲーション、ダイアログ、保存データ、テーマ、デバイス情報
$form現在の画面/フォーム: 変数、メッセージング、画面遷移
$vmデータ: データソースの読み書き、データのリクエストと購読
$http外部APIへのネットワークリクエスト(get、post、put など)
$logデバッグ用のログメッセージ(d、i、w、e)の出力
$mqttリアルタイムメッセージング(connect、subscribe、publish)
$act「animation mode」タブに登録したアクションや状態遷移の実行
$log.d("Button was tapped!"); // デバッグログを出力

$app.openPage("dashboard"); // dashboardページに移動

$http.get("https://api.example.com/user", function(res) {
$log.i(res); // レスポンスを使って処理を行う
});

各グローバルオブジェクト($app、$form、$vm、$act、$log、$http、$mqtt)の全メソッドとプロパティは、11. Script APIドキュメントのGlobal Objectsセクションで確認できます。

ウィジェットオブジェクトの制御

  • キャンバス領域に配置した特定のウィジェット(ボタン、テキスト、チェックボックスなど)を表します。このオブジェクトは、所属する画面上にのみ存在し、idを通じてのみアクセスできます。すべてのウィジェットオブジェクトは、その機能をプロパティ・メソッド・イベントという3種類のメンバーとして公開します。この3つを理解することが、あらゆるウィジェットをスクリプトで操作する鍵です。パターンさえ分かれば、どのウィジェットも同じように扱えます。

ウィジェットごとの全プロパティ・メソッド・イベントの一覧は、11. Script APIドキュメントのWidgetセクション(Widget and Component Reference)で確認できます。

  1. プロパティ: ウィジェットの状態を読み取り・変更する — ユーザーのイベントに応じてプロパティを設定・取得できます(例: ボタンのクリックで、指定したテキストのカラーを変更する)。

    1. プロパティはさまざまなメソッドで設定・取得できます。ショートカットがないプロパティは、.setPropertyと.getPropertyをそのまま使います。設定・取得したいプロパティをパラメーターとして渡します。

      // プロパティ名をパラメーターとして渡し、特定のプロパティを設定する
      // プロパティ名をパラメーターとして渡し、特定のプロパティを取得する
      textWidgetId.setProperty(propertyName, value);
      textWidgetId.getProperty(propertyName);

      textWidgetId.setProperty("text", "Hello World");
      var textProp = textWidgetId.getProperty("text");

      // 一部のよく使うプロパティには、ショートカットメソッドもあります(下記の
      // Methodsを参照)。例えば .setText("Hello World") は
      // .setProperty("text", "Hello World") のショートカットです。注意: すべての
      // プロパティにショートカットがあるわけではありません。ない場合は .setProperty / .getProperty を使います。
    2. スクリプトからスタイルプロパティを設定・取得することもできます。SizedBox、Padding、DecoratedBoxなどのプロパティです。これらをスクリプトから取得・設定するには、対象のスタイルプロパティがウィジェットにあらかじめ存在している必要があります。存在しない場合、スクリプトは何も効果を持ちません。

      // スタイルプロパティを設定するときは、そのスタイルがあらかじめ設定されている必要がある
      widgetId.setStyleProperty(styleName, styleProperty, value);
      widgetId.getStyleProperty(styleName, styleProperty);

      // カラーを設定するときは、hex値を使うか、
      // カラーテーマに登録されたカラー名を使える
      widgetId.setStyleProperty("DecoratedBox", "decoration.color", "#FFFFFF");
      widgetId.getStyleProperty("DecoratedBox", "decoration.color");
  2. メソッド: ウィジェットに組み込まれた動作。基本的に括弧を付けて呼び出す — ウィジェットに何かを実行するよう指示します。引数を渡すことができ、一部のメソッドは保存できる結果を返します。

    ウィジェットメソッド
    TimerwidgetId.start();
    CalendarwidgetId.goToToday();
    ListViewwidgetId.insert(index);
    Text(プロパティのショートカット)widgetId.setText(”Hello World”);
    • 注意: 各ウィジェットで利用できるプロパティ・メソッド・イベントの全一覧は、Properties, Methods & Eventsのリファレンス全体を参照してください: 11. Script APIドキュメント
  3. イベント: 関数を割り当てる対象

    • イベントは、ユーザーがウィジェットを操作したときに発火します。応答するには、イベントに関数を割り当てます。するとLucyは、イベントが発生するたびにその関数を実行します。一部の関数はパラメーターを受け取り、それをその後の処理に使えます。
    • これは、ページがユーザーに反応するための主要な方法です。イベントの全一覧、渡される引数、実際のバインド例については、次のサブセクションイベントの処理を参照してください。

イベントの処理(タップ、入力変更など)

バインドの仕組み

  • イベントは、ユーザーがウィジェットを操作したときに発火します。応答するには、イベントに関数を割り当てます。するとLucyは、イベントが発生するたびにその関数を実行します。
  • バインドは常にonStart関数の中で設定してください。そうすることで、ページの初期化時に関数がすぐにイベントへバインドされます。
  • onChangedonSelectedonSubmittedなどの場合は、ハンドラーに引数を渡せます(例: valueindexdate)。

よく使うウィジェットイベント

  • ウィジェットにあらかじめ設定されたイベントがある場合、そのウィジェットをクリックするとプロパティパネルに表示されます。この種のイベントは通常「on」で始まります。イベントが表示されない場合、そのウィジェットには設定済みのイベントがないということです。その場合はonTapイベントを使えます。
ウィジェットイベント渡される引数
ButtononClick
Checkbox, TextFieldonChangedvalue
TextFieldonSubmittedvalue
ListViewonSelectedindex
Text、Icon、Row、Column などonTap

ウィジェットタイプ別の詳しい一覧:

グループイベント
ボタン/選択onClick, onSelected
テキスト入力(TextField)onChanged, onSubmitted, onEditingComplete, onTap, onFocusOut
トグル/ピッカーonChanged (Checkbox, Switch, DropDown, Slider, Radio)
スライダーonChangeStart, onChangeEnd
リスト/スクロールonScrollEnd, onReorder, onOverflowChanged
ナビゲーション/時間onPageChanged, onDateSelected, onExpired (Timer)

ハンドラーのバインド

  • イベントに関数を割り当てる方法は2つあります。インラインで定義するか、別に宣言して名前で参照するかです。どちらも同じ結果になります。
// 1) インライン: onStart() の中でハンドラーを直接定義する
function onStart() {
widgetId.onClick = function() {
$log.d("submit tapped");
};

widgetId.onChanged = function(value) {
$log.d("field is now: " + value);
}
}

// ================================================================
// 2) 分離: 関数を宣言し、名前で参照する
function onStart() {
widgetId.onClick = button_onClick;
widgetId.onChanged = checkbox_onChanged;
}

function button_onClick() {
$log.d("button clicked!");
}

function checkbox_onChanged(value) {
$log.d("field is now " + value);
}

条件分岐・ループ・ユーティリティ関数の使用

よく使うパターン(スクリプトで使うJavaScriptの基礎)

JavaScriptに慣れていない方向けに、以下のスニペットは標準的な言語機能をハンドラー内で使うとどうなるかを示しています。コーディングに自信がある方は読み飛ばして構いません。純粋なJavaScriptであり、独自仕様の対応物を探す必要はありません。

条件分岐 — 条件を満たしたときだけ何かを実行します(例: チェックボックスの状態を読み取り、別のウィジェットを表示または非表示にする)。

function checkbox_onChanged(value) {
if(value === true) {
detailsBox.setProperty("visible", true);
detailsBox.visible = true; // visibleプロパティはこの方法でも設定できる
} else {
detailsBox.setProperty("visible", false);
detailsBox.visible = false; // visibleプロパティはこの方法でも設定できる
}
}

三項演算子 — 2つの値のいずれかを返す、コンパクトなif/elseです。

function checkbox_onChanged(value) {
// チェックされていれば "On"、そうでなければ "Off" を表示
statusLabel.setText(value === true ? "On" : "Off");
}

ループ — 動作を繰り返します。例えばリストに複数の行を追加します。

function onStart() {
var fruits = ["Apple", "Banana", "Cherry"];
for (var i = 0; i < fruits.length; i++) {
$log.d("Item " + i + ": " + fruits[i]);
}
}

オブジェクトとJSONの扱い — レスポンスをパースして、そのフィールドを読み取ります。

function onStart() {
var jsonText = '{ "name": "Jane", "age": 30 }';
var user = JSON.parse(jsonText); // テキスト → オブジェクト
nameLabel.setText(user.name); // "Jane"

var backToText = JSON.stringify(user); // オブジェクト → テキスト
$log.d(backToText);
}

共有スクリプトの使用

共有モジュールの作成

プロジェクトが大きくなると、複数の画面で同じスクリプトのまとまり(ログイン、ヘルパー関数など)を使いたい場合が出てきます。同じコードを各ページのスクリプトウィンドウにコピー&ペーストする代わりに、共有可能なスクリプトファイルにまとめられます。そのファイルからコードをインポートすれば、そこで宣言した関数を複数の画面から利用できます。

  • Scriptタブで新しい.jsファイル(例: common.js)を作成します。
  • 他のスクリプトと同じく、プロジェクトのスクリプトアセットフォルダーに保存されます。
  • require('jsFileName')は、インポートを行うファイルの先頭に置く必要があります。ファイル名をパラメーターとして渡します。
  • インポートできるファイル数に制限はありません。
  • 関数は次のように宣言できます:
const Util = {
getToday : function() {
let today = new Date();
return today;
},
getTime : function() {
let today = new Date();

let hour = ("0" + today.getHours()).slice(-2); // 時
let min = ("0" + today.getMinutes()).slice(-2); // 分
let sec = ("0" + today.getSeconds()).slice(-2); // 秒

return hour+ "" +min+ "" +sec;
}
}

インポートする — スクリプトの一番上、他のコードより前に置き、必要な場所で呼び出します:

require('common.js');

function onStart() {
button.onClick = setCurrentTime;
}

function setCurrentTime() {
let time = Util.getTime(); // Util は common.js から来る

time_txt.setProperty("text", time);
}

スクリプトのデバッグ

よく使うデバッグパターン

関数が呼び出されているか確認する:

最も簡単な確認方法です。実行されていないと思われる関数の先頭にログを追加します:

function myButton_onClick() {
$log.d("myButton_onClick fired");
// 残りのロジック
}

データフローを追跡する:

重要な操作の前後にログを出力し、データがどこで変化・停止するかを突き止めます:

$log.d("before sort: " + $vm.getDSValue("myDS.body.items[0].title"));
$vm.sortString("myDS", "body.items.title", "ascending");
$log.d("after sort: " + $vm.getDSValue("myDS.body.items[0].title"));