Using Moustache in Subflow fields for dynamic and explicit content?

Hello,
(First thanks for Node-RED an amazing tool I use for personal project for 5 years)

I love default nodes and subflow mechanism, but I struggle on the same issues/pattern :
[a Function Node to Set msg.val.ues] => [a stand node like HTTP or Subflow]

I'd love to remove this "glue" to chain only my subflows but I don't understand how I could use dynamic variable from msg.* into my subflow ?

I give a try to Moustache like HTTP Node but it doesn't work:

image

What is the best practice ?At the moment I do env.get('my-var') || msg['my-var'] but I still have to prepare msg['my-var'].

  • Is there a way to run Moustache on env.get('my-var') ?
  • Or should I call setMessageProperty() on it ?
  • Or have msg. field type in subflow (but I understand it's static)
  • Or expression field type (and do $string(payload[my-var])

I think it's more readable to explicitly set in the subflow instance my data is in msg.x.y than read it magically from msg object.

Many Thanks !

You can use a template node. See documentation.

Maybe I am misunderstanding what you are trying to accomplish. There is a documentation section about environment variables.

Note that these are only expanded once, upon deploy. It behaves like a "replace this with this" it is not "dynamic".

Let me explain an other way :

  • A subflow can only have static variable (string, int, env, etc ...) set as env
  • A subflow have acces to "msg" from flow

If I design a generic sublow like a FaceRecognition subflow (that only do a REST request).

  • I don't want to use in my subflow msg.my-parameter because in my master flow I would have to setup msg.my-parameter in a Function or Change node.
  • I'd love a [msg.] field in my subflow to gather the right data in my master flow
  • or a [string] field (my subflow will do the eval() or getMessageProperty()
  • or something else dynamic

The only issue I have with Node-RED is there is too many Function node to glue things together. Sometimes, often, that's not required if we could use subflow fields.

You can set up a string field to reference the incoming msg property you would like to use in the subflow. So when you use a new copy of the subflow you just type the msg property you want the subflow to use.
e.g.

[{"id":"43d574be.4067ac","type":"subflow","name":"Subflow 1","info":"","category":"","in":[{"x":160,"y":140,"wires":[{"id":"7665008.a988d"}]}],"out":[{"x":460,"y":160,"wires":[{"id":"7665008.a988d","port":0}]}],"env":[{"name":"msg_in","type":"str","value":"normal","ui":{"type":"input","opts":{"types":["str"]}}}],"color":"#DDAA99"},{"id":"7665008.a988d","type":"function","z":"43d574be.4067ac","name":"","func":"let msg_in = msg[env.get(\"msg_in\")];\nmsg.payload = msg_in\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":320,"y":160,"wires":[[]]},{"id":"18f08d85.db084a","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"normal","v":"{\"test\":1}","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":160,"y":4600,"wires":[["c233f4f0.d42cb8"]]},{"id":"c233f4f0.d42cb8","type":"subflow:43d574be.4067ac","z":"b779de97.b1b46","name":"","env":[],"x":380,"y":4600,"wires":[["ae4ef9b4.4bd328"]]},{"id":"ae4ef9b4.4bd328","type":"debug","z":"b779de97.b1b46","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":630,"y":4420,"wires":[]},{"id":"6339434e.0dcb24","type":"subflow:43d574be.4067ac","z":"b779de97.b1b46","name":"","env":[{"name":"msg_in","value":"another","type":"str"}],"x":380,"y":4660,"wires":[["ae4ef9b4.4bd328"]]},{"id":"124399ec.8baf5e","type":"inject","z":"b779de97.b1b46","name":"","props":[{"p":"another","v":"{\"test\":2}","vt":"json"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":163.3333282470703,"y":4654.33349609375,"wires":[["6339434e.0dcb24"]]}]

Yes that's what I did :
RED.util.getMessageProperty(msg, env.get('env-debug-str'))

I rather like getMessageProperty() because it handle deep syntaxe. But it's not perfect because it's hard to detect if it's a real string (static value) or a msg.*** string. I don't understand why there is no msg.* field type for subflow ?

The other issue is payload, I use to build a payload for an HTTP Request in a Function Node:

msg.payload = {
    'name'     : msg.FacePerson.fields.Name,
    'userData' : msg.FacePerson.fields.UserData
}

That's something that would be really cool to do in a JSON field instead of using a change node before. It's just mixing / reorganizing stuff

Because Subflow properties are not dynamic. They are evaluated when the flow is deployed and their values cannot change.

Yes that what I understand reading other messages. And I assume you can't run a RED.util.getMessageProperty(msg, env.get('env-debug-str')) when calling the node because env vars are imutable.

My best bet is to write a CUSTOM.getMessageProperty(msg, prop) that wrap getMessageProperty, try/catch errors and return the prop itself if there is results. For each of my subflow's fields

You can do that with the Template node, configured to parse the result as JSON.

Yes there is many ways to do that Function, Template, Change node, etc ...
I try to improve readability of my flow, and remove cluster of [Node doing configuration] + [Node doing] actions.

I'm proud of that one that send "chat messages" to a smart mirror :

But not happy with that one that send action to the smart mirror :
image

(Yes function node can be replaced by something else), but for an elegant / readable flow it's just a matter of picking fields from the msg.* most of the time

(BTW I love current subflow fields added in Node-RED compared to previous version it's a game changer, thanks !)