JavaScript
JSON
mustache
node-red
lambda式

Node-redのmustacheテンプレート中でeval的な事をしたい時はLambda式を使うと嬉しいです

前提

Node-redでHTMLを動的に生成したい場合に一応Mustacheテンプレートまでは使って見たけれど、微妙に痒いところに手が届かないという人向けです。

状況

例えば、以下のようなPayloadを表にしたいとします。

{
    "payload": [
        {
            "serial": 1,
            "lank": "bronze",
            "lastname": "tanaka",
            "firstname": "taroh",
            "phone": "090-0000-0000"
        },
        {
            "serial": 2,
            "lank": "gold",
            "lastname": "suzuki",
            "firstname": "jiroh",
            "phone": "090-0000-0001"
        },
        {
            "serial": 3,
            "lank": "silver",
            "lastname": "yamada",
            "firstname": "hanako",
            "phone": "080-0000-0000"
        }
    ]
}

上記のJSONだった場合、mustacheテンプレートは

{{#payload}}
  <tr>
    <td>{{serial}}</td>
    <td>{{lank}}</td>
    <td>{{lastname}}</td>
    <td>{{firstname}}</td>
    <td>{{phone}}</td>
  </tr>
{{/payload}}

とやれば、(前後のtableタグと一行目はまぁどこかに書いてあるとして)

serial lank lastname firstname phone
1 bronze tanaka taroh 090-0000-0000
2 gold suzuki jiroh 090-0000-0001
3 silver yamada hanako 080-0000-0000

みたいな表になるためのHTMLが出来てくるわけです。
ここまではまぁ普通の便利な使い方です。

ここで、例えばLankが、外部キー的になってた場合どうするのか?

つまり、

serial lank lastname firstname phone
1 3 tanaka taroh 090-0000-0000
2 1 suzuki jiroh 090-0000-0001
3 2 yamada hanako 080-0000-0000
serial lankname
1 gold
2 silver
3 bronze

みたいなデータ構造になるってわけです。まぁ普通はこういう構造の方が多いですよね。
で、そのときにどうやってスマートに描画するか?
そこでLambda式を使います。

まず、templeteノードよりも前にFunctionノードを用意して、

msg._render = function(){
    return function(text, render){
        return render("{{" + render(text) + "}}") ;
    }
};
return msg;

としておきます。
あと、前提となるデータとして

{
    "payload": [
        {
            "serial": 0,
            "lank": 2,
            "lastname": "tanaka",
            "firstname": "taroh",
            "phone": "090-0000-0000"
        },
        {
            "serial": 1,
            "lank": 0,
            "lastname": "suzuki",
            "firstname": "jiroh",
            "phone": "090-0000-0001"
        },
        {
            "serial": 2,
            "lank": 1,
            "lastname": "yamada",
            "firstname": "hanako",
            "phone": "080-0000-0000"
        }
    ]
}

ってのと(さっきとはlankの中身が変わってます)、それに加えて

{
    "lanklist": [
        {
            "serial": 0,
            "lankname": "gold"
        },
        {
            "serial": 1,
            "lankname": "silver"
        },
        {
            "serial": 2,
            "lankname": "bronze"
        }
    ]
}

というのも用意しておきます。
その状態で、mustacheを以下のようにします。

{{#payload}}
  <tr>
    <td>{{serial}}</td>
    <td>{{#_render}}lanklist.{{lank}}.lankname{{/_render}}</td>
    <td>{{lastname}}</td>
    <td>{{firstname}}</td>
    <td>{{phone}}</td>
  </tr>
{{/payload}}

このlanklist.{{lank}}.lanknameのところを{{#payload}}のリストとして評価すると、最初はlanklist.0.lanknameというテキストになります。それを{{#_render}}の箇所でlambda式に突っ込むわけです。
中身はrender("{{" + render(text) + "}}")なので、つまりrender("{{lanklist.0.lankname}}")を評価せい、という事で、めでたくgoldという文字列に置き換わってくれるという事になります。

以上ですが、、

ぶっちゃけ、今回の実装であればlanklistのserialは管理上の為だけで、無いなら無いでもOKのはずなのです。。。
JSONata的な検索ができるんならば、別な表現も出来そうですね。。
まぁその内良いアイデアが浮かぶと思いますので、その時までは一旦これで勘弁してください。。

では。