Node-REDのカスタムノード でEditableListを使う時にハマりやすいポイント

Node-REDに`EditableList`という、データを追加していくことができるリストの機能があります。
（https://nodered.jp/docs/api/ui/editableList/ ）

これですが、実際使うにはドキュメントに書かれていないことが結構あり、ドキュメントだけをみて開発を進めていくのはしんどいものがあった。
実際に使われているノードを参考にし、なんとか動くところにまで漕ぎ着けたけど、再度やるときにつまづきそうなので書き残しておきます。

参考にしたノードは以下です

* https://github.com/node-red/node-red/blob/master/packages/node_modules/%40node-red/nodes/core/function/10-switch.html
* https://github.com/nec-baas/node-red-contrib-nec-baas/blob/master/nebula-object-storage.html

# 注意するポイント

特にハマったのは以下のポイント

* `oneditprepare`と`oneditsave`両方を使う必要がある
* EditableListは`input type="text"`で作ったインプットのように自動でデータの保持、表示などは行ってくれない
* defaultの名前とid名のルールに従わないと、デプロイボタンが押せない（データ保持ができない）

Node-REDのUIを作ってると、なんか知らんけどデータが保持されて、データが挿入されていたりしますが、それらはEditableListには適用されません。
UIのAPIとして用意されていますが、あくまでUIの提供だけで、**その他の実装は自分で頑張れ**が基本になっています。

**設置すりゃなんとかなるだろ**みたいな気持ちでいると**「あれ、なんで動かないの」**ってことになります。

ではそれぞれについて説明していきます。

# `oneditprepare`と`oneditsave`両方を使う必要がある

oneditprepareとは、「on edit prepare」、oneditsaveは「on edit save」が区切りなしになったものです。
前者はedit画面が表示されたときに実行され、後者は「完了」ボタンが押されたときに実行されます。

なぜどちらとも必要かというと、

**oneditprepareでUIの作成や、既存データの表示**
**oneditsaveで入力されたデータの保持**
を行う必要があるからです。

# データの保持と表示のしくみ

コードを参考にしながら説明していきます。

以下の「AddItem」ではEditableListに行を追加したときにのコードが書かれています
上記でいう「UIの作成」です
https://github.com/nec-baas/node-red-contrib-nec-baas/blob/9dd14d37ac6fc88df6ae8662547d702c10587525/nebula-object-storage.html#L201

そして以下の場所で
データがあれば、データ行を作るよう指示しています
https://github.com/nec-baas/node-red-contrib-nec-baas/blob/9dd14d37ac6fc88df6ae8662547d702c10587525/nebula-object-storage.html#L277

そして、既存データがあった場合は以下の場所でデータ挿入を行っています
https://github.com/nec-baas/node-red-contrib-nec-baas/blob/9dd14d37ac6fc88df6ae8662547d702c10587525/nebula-object-storage.html#L248

そしてデータ保持を行っているのは以下の場所です
`oneditsave`の最後の行で`node.rules.push(r);`をして、データを保持しています。
https://github.com/nec-baas/node-red-contrib-nec-baas/blob/9dd14d37ac6fc88df6ae8662547d702c10587525/nebula-object-storage.html#L282

## 実際の操作の流れでみてみる

1. ユーザがノードの編集画面を開く。このとき`oneditprepare`が実行される
2. ユーザが行を追加。`AddItem`が実行されて、ユーザが入力できる行が生まれる
3. ユーザがデータを入力
4. ユーザが完了ボタンを押します。このとき`oneditsave`が呼ばれてデータを保持
5. 再びユーザが編集画面を開く
6. `oneditprepare`が実行され、既存データがあるのでAddItemをその個数分叩く処理が実行される
7. 追加された行に既存データが挿入される

という流れになります。
行ったり来たりして少し面倒ですが、保持と表示の役割に分かれて動いていることを理解すると結構わかりやすくなります。

# defaultの名前とid名のルールに従わないと、デプロイボタンが押せない（データ保持ができない）

これはいまいちまだルールが理解できていないんだけど
EditableListを使う場合以下のように

divには `node-input-xxxxxxx-container-row`
EditableListになるolには `node-input-xxxxxxx-container`
と名付ける。

```
<div class="form-row node-input-rule-container-row"><!-- -row がある -->
   <ol id="node-input-rule-container"></ol><!-- -row が無い -->
</div>|
```

また、defaultの値には
xxxxの複数形となる値を入れる

```
defaults: {
	name: { value:"object"},
	bucketName: { value: ""},
	isClause: { value: false},
	rules: { value:[{t:"eq", v:""}]},  // ここ！ rule"s"になってる
	operator: { value: "AND"},           
	sortKey: { value: ""},
	sortType: { value: "ASC"},
	skipCount: { value: 0},
	limit: { value: 100},
	projection: { value: ""}
},
```

こうすることできちんと認識され、デプロイボタンが作動するようになる。
rulesがruleの場合は動作しなかったので注意が必要。

# データの取得方法

jsファイルからは、configから代入したプロパティ名で取得が可能です。

仮に、以下のようなfunctionを書いていて、htmlでは`node.lists`に代入していたた場合は
config.listsでデータへのアクセスができます。

```
function HogehogeCreateNode(config) {
  config.lists //とれた！ 
}
```

# まとめ

最低限の実装はここまでのものを注意すれば作ることができました。
他にも見た目がーとかいろいろあるとはおもいますが、まずは動くことが大事！
これからノードを作る人の参考になれば幸いです。では！