クライアントサイドでのJavascriptを使用したビジネスロジック
このガイドで学べること
このガイドでは、アプリのクライアント(フロントエンド)側でビジネスロジックをJavascriptを使用して実装する方法を示します。ロジックノードを使用してノーコードでビジネスロジックを構築す ることも可能ですが(このガイドで説明されています)、ビジネスロジックはコード形式で表現した方が理解しやすいことが多いため、Javascriptの使用がしばしば推奨されます。このガイドでは、FunctionおよびScriptノードを使用して、Noodlでコードとノーコードを組み合わせる主な方法を取り上げます。 また、コード世界とノード世界の両方で状態データに簡単にアクセスできるようにする主な方法であるComponent Objectノードも重要です。
概要
このガイドでは、リスト上でのシンプルなマルチセレクトの相互作用と、削除やコピーなどのいくつかのマルチセレクト操作を実装します。ビジネスロジックはマルチセレクト自体(選択、選択解除)およびリストの内容に対する操作を扱います。また、画面上のButtonsの状態制御も行います。
リスト、配列、オブジェクトなど、さまざまなNoodlのコンセプトを使用しますので、これらのガイドを先に確認しておくと良いでしょう(List guide, Array guide, Object guide)。もちろん、Javascriptも使用しますし、特に配列関数を多用するので、それらについてもチェックしておく価値があります。良いドキュメントの例としては、こちらがあります。
Scriptノードに関する専用ガイドもあります。こちらを参照してください。
マルチセレクトUIを持つリストの作成
この例では、例えばeコマースシステムでの、order_nbr、quantity、delivery_dateを持つ注文のシンプルなコレクションを扱います。アプリは注文をリスト表示し、ユーザーが標準的なマルチセレクトの相互作用を使用して複数の注文を選択できるようにします。選択した注文は、削除、コピー、または_マージ_することができます。実際の操作がどういう意味を持つのかは、実装していく中で詳しく見ていきます。また、全ての項目を_選択_または_選択解除_することも可能です。
基本データ
このガイドでは、作業したい基本データセットを追加して始めます。データを保持するためにStatic Arrayを使用しますが、本質的にこのデータはクラウドデータベースから来たものかもしれません。"Hello World"テンプレートを使用 して新しいプロジェクトを開始します。Static Arrayノードを追加し、JSONフォーマットに設定し、以下のデータを追加します:
[
{"order_nbr":"A-12124", "quantity":2, "delivery_date":"2022-10-23"},
{"order_nbr":"A-26232", "quantity":6, "delivery_date":"2022-10-25"},
{"order_nbr":"V-23532", "quantity":3, "delivery_date":"2022-09-13"},
{"order_nbr":"B-99243", "quantity":5, "delivery_date":"2022-08-03"},
{"order_nbr":"V-35124", "quantity":1, "delivery_date":"2022-12-20"},
{"order_nbr":"G-23421", "quantity":1, "delivery_date":"2022-09-09"},
{"order_nbr":"B-86612", "quantity":8, "delivery_date":"2022-11-21"},
{"order_nbr":"C-61633", "quantity":5, "delivery_date":"2022-05-29"},
{"order_nbr":"V-42241", "quantity":2, "delivery_date":"2022-11-15"},
{"order_nbr":"V-99112", "quantity":12, "delivery_date":"2022-12-20"},
{"order_nbr":"A-51512", "quantity":1, "delivery_date":"2022-07-07"},
{"order_nbr":"B-00914", "quantity":8, "delivery_date":"2022-09-13"},
{"order_nbr":"C-11121", "quantity":9, "delivery_date":"2022-10-19"}
]
これでシステムにいくつかの注文が入りましたので、UIの構築を
始めましょう。マルチセレクトリストから始めます。
マルチセレクトリストの構築
リストに表示されるアイテムの配列を示すコンポーネントを構築したいと思います。また、選択されているアイテムを追跡する機能も必要です。以下にその機能を概説します。
- アイテムがリストに表示されるようにする機能。アイテムの前にはチェックボックスが表示されます。
- 初期選択を指定できる機能、つまり、どのアイテムが最初に選択されるべきかを指定できます。
- アイテムを選択または選択解除すると、コンポーネントはシグナルを発生させ、現在選択されているアイテムのArrayを提供します。
- すべてのアイテムを選択または選択解除するために、シグナルをトリガーできます。
マルチセレクトリストがどのアイテムが選択されているかをどのようにエンコードするかという問題があります。一つの方法は、マルチセレクトリストが選択されているアイテムのArrayを以下のフォーマットで提供することです:
{
"Value":<選択されたオブジェクトのid>
}
例えば、リストに"111"、"222"、"333"のidを持つ3つのアイテムがあり、最初と2番目のアイテムが選択されている場合、コンポーネントからの出力は以下のようになります:
[
{
"Value":"111"
},
{
"Value":"222"
}
]
完了すると、外側から見たときのコンポーネントは以下のようになります:

選択ロジック
コンポーネントに必要なロジックを考えてみましょう。内部的には、どのアイテムが選択されていて、どれが選択されていないかを追跡する必要があります。これは、上記のArrayを生成するためだけでなく、正しく視覚化するためにも必要です。
もちろん、選択状態をアイテム自体に直接保存することもできますが、それは実際にはあまり良い設計ではありません。アイテムが複数のマルチセレクトリストの一部である場合はどうなるでしょうか ?また、アイテムをデータベースに保存することになった場合、選択状態も誤って保存する可能性がありますが、それは全く意味がありません。
より良い設計は、選択状態を追跡するために各注文を別のObjectで"ラップ"することです。その後、元のアイテムではなく、これらのオブジェクトのリストを表示します。"ラッパー"は当然、それがラップするObjectのIdを保存する必要があります。ラッパーのフォーマットは以下のようになります:
[
{
"Checked":<アイテムがチェックされているかどうかに応じてtrueまたはfalse>,
"Value":<それがラップするObjectのid>
}
]
したがって、上記の例でid "111"、"222"、"333"を持つアイテムがあり、最初の2つがチェックされている場合、チェックボックスの配列は以下のようになります:
[
{
"Checked":true,
"Value":"111"
},
{
"Checked":true,
"Value":"222"
},
{
"Checked":false,
"Value":"333"
},
]
要約すると、マルチセレクトリストコンポーネントには内部で以下のロジックが必要です
- 新しいアイテムでリストが供給されると、アイテムごとに1つの新しいチェックボックスArray(ラッパーObject)を作成し、初期選択に応じて
Checkedをtrueまたはfalseに設定します。 - 各アイテムを表示するリストアイテムは、
Checkedプロパティを使用してアイテムのチェック状態を視覚化します。ユーザーがチェックボックスをクリックすると、Checkedプロパティがトグルされます。 - チェック状態が変更されるたびに、マルチセレクトリストはチェックされたアイテムのみを保持する新しいリストを生成する必要があります。この形式は、上記のように、
[{"Value":<チェックされたアイテムのid>}, ...]です。これは外部世界に提示されます。
"Multi Select List"という名前の新しいビジュアルコンポーネントを作成
して始めましょう。

これで、ほぼ空のコンポーネントができました。Component InputsとComponent Outputsを追加します。これらに何を含めるべきかは既にわかっています。つまり、コンポーネントとのやり取り方法です。したがって、Component InputsにSelection、Items、Select All、Clear Selectionのポートを追加します。

Component Outputsでは、SelectionとSelection Changedのポートを作成します。

これで、Javascriptロジックの記述を始める準備が整いました。Scriptノードを追加します。

2つの入力を追加します。1つはリストに表示するItems、もう1つはリストに最初に選択されるべきアイテムを含むInitialSelectionです。どちらもArrayタイプです。

さあ、コーディングを始めましょう!最初に行いたいのは、チェックボックスリスト、つまり各アイテムのチェック状態を保持するラッピングObjectsのArrayを生成することです。
セッター関数 - 入力が変更されたときにコードを実行する
Items入力が変更されるたびにそのArrayを生成したい場合、_セッター_関数を使用して特定の入力が変更されるたびにスクリプトの一部を実行できます。これらは以下の形式で宣言されます:
Script.Setters.<プロパティ名> = function (value) {...}
この場合、Itemsが変更されるたびにチェックボックスArrayを生成したいので、スクリプトファイルに以下のコードを追加します:
Script.Setters.Items = function (items) {
if(!Script.Inputs.Items) return
// 入力された**Items**を走査し、それぞれのアイテムに対して新しいラッパー**Object**を作成します (`Noodl.Object.create`を使用)。
// チェック状態を確認し、初期選択配列に対して`true`または`false`を設定します。
// また、ラップされた**Object**へのポインタを`Value`プロパティに保存します。
}
このコードは、入力されたItems(Script.Inputs.Itemsを通じて参照される)を通過し、それぞれに対して新しいラッパーObject(Noodl.Object.createを使用)を作成します。チェック状態を確認し、初期選択配列に基づいてtrueまたはfalseに設定します。また、ラップされたObjectへのポインタをValueプロパティに保存します。
undefined入力のチェック
スクリプトノードの入力がまだ設定されていない場合(この場合のItems入力やInitialSelectionなど)、それらはundefinedの値を持ちます。コード内でこのケースを明示的にチェックすることは、しばしば良いアイデアです。
ここでの小さなトリックは、ラッパーObjectのidを明示的に設定していることです。実際には、idが指定されていない場合、Noodlは新しいidを生成します。しかし、独自のidを作成することで、特定のオブジェクトをラップするラッパーオブジェクトごとに一意だが同じになるため、古いObjectsを再利用するのではなく新しいものを作成します。
結果として得られるArrayはComponent.Object.Checkboxesに保存されます。これには特に注意が必要です。
スクリプト内でのコンポーネントオブジェクトの使用
Noodlの各コンポーネントには、一意のComponent Objectがあります。通常のObjectとは対照的に、Component Objectは_コンポーネント自体またはコンポーネントの子を使用してのみアクセスできます_。これにより、スコープが作成され、他のコンポーネントが誤ってこのオブジェクトにアクセスするリスクがありません。例えば、同じ画面に2つのマルチセレクトリストを表示する場合、通常のObjectを使用してチェックボックスを保存すると、2つのリストでチェックボックスが異なる可能性があるため、Objectsに一意のidを持たせる必要があります。この問題を完全に回避するために、
Component Objectにチェックボックスを保存します。
すべてのコンポーネントにはComponent Objectがあり、ノードワールドでComponent Objectノードを追加することでアクセスできます。したがって、一旦Scriptノードを閉じて、Component Objectノードを追加しましょう。また、Component ObjectにCheckboxesプロパティを追加します。
これまでに行ったことをテストするために、Arrayノードを追加し、Component ObjectのCheckboxesプロパティをそれに接続します(Itemsプロパティを介して)。次に、Multi Select Listコンポーネントをメインアプリに追加します。Static Arrayのアイテムを接続してアイテムを提供します。すべてが正しく設定されていれば、いくつかのチェックボックスアイテムがArrayに流れ込むはずです。