# Subflows and configuration: late and runtime parameters binding

**URL:** <https://discourse.nodered.org/t/subflows-and-configuration-late-and-runtime-parameters-binding/60042>\
**Category:** Share Your Nodes\
**Created:** [18 March 2022 16:19 UTC](https://discourse.nodered.org/t/subflows-and-configuration-late-and-runtime-parameters-binding/60042 "2022-03-18T16:19:50Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![msillano](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/msillano/32/17424_2.png) [@msillano](https://discourse.nodered.org/u/msillano)\
**Post date:** [18 March 2022 16:19 UTC](https://discourse.nodered.org/t/subflows-and-configuration-late-and-runtime-parameters-binding/60042/1 "2022-03-18T16:19:50Z")

</div>

## The problem

To make the life better, and to make flows more robust, with a single centralized update, I make use of configuration/options constants.

But where to place configuration data?

### Environement

- **pros:** standard. Environment variables can be used as subflow parameters.
- **cons:** complex installation. To update you must exit node-red and do some oprations (O.S. drpendant).

Not for all user, only valid for few and constant values (e.g. username), not for user options.

### Global context

- **pros:** easy to set and update inside node-red, e.g. using the **node-contrib-config** , very friendly.
- **cons:** based on the current subflow [implementation](https://nodered.org/docs/user-guide/environment-variables), parameters cannot come from the global context.

## my solution

Until the subflow implementation does [not change](https://discourse.nodered.org/t/jsonata-in-subflow-interface/59813), I have found a simple workaround: a node-function that does a late binding (at runtime) of some/all parameters of a subflow, so we can implement an indirect parameter definition and use the **node-contrib-config** to manage the options.

## features

**late binding:**

1. if the subflow has a parameter whose value (string) start with:

**runtime update:**

1. if the incoming `msg` contains `msg.<paramName>:tempvalue`  
then `tempvalue` is temporarily assigned to parameter (optional).

2. the dynamic value can be obtained inside the subflow using `flow.get(<paramName>)` (instead of `env.get(<paramName>`), still valid for static parameters).

## use

In your subflow:

1. Put a 'late blinding' function node between the msg input and your nodes.
2. Update the function code, adding at end one line for any dynamic parameter:

```auto
       _upadateParam(<dynamicName1>); 
       _upadateParam(<dynamicName2>); 

```

1. If you are updating an existing subflow, replace all `env.get(<dynamicNameX>` with `flow.get(<dynamicNameX>`.

Enjoy

`````auto
[
    {
        "id": "faaa7cdb933cb272",
        "type": "subflow",
        "name": "late binding example",
        "info": "Subflows and configuration: late and runtime parameters binding.\n\n## The problem\nTo make the life better, and to make flows more robust, with a single centralized update, I make use of configuration/options constants.\n\nBut where to place configuration data?\n\n### Environement\n- **pros:** standard. Environment variables can be used as subflow parameters.\n- **cons:** complex installation. To update you must exit node-red and do some opration (O.S. drpendant).\n\nNot for all user, only valid for few and constant values (e.g. username), not for user options.\n\n### Global context\n- **pros:** easy to set and update inside node-red, e.g. using the **node-contrib-config** , very friendly.\n- **cons:** based on the current subflow [implementation](https://nodered.org/docs/user-guide/environment-variables), parameters cannot come from the global context.\n\n## my solution\nUntil the subflow implementation does [not change](https://discourse.nodered.org/t/jsonata-in-subflow-interface/59813?u=msillano), I have found a simple workaround: a node-function that does a late binding (at runtime) of some/all parameters of a subflow, so we can implement an indirect parameter definition and use the **node-contrib-config** to manage the options.\n\n## features\n **late binding:** \n 1. if the subflow has a parameter whose value (string) start with:\n - `global.`\n - `flow.`\n - `msg.`\n this function calculates the actual value and assigns it to the parameter.\n\n **runtime update:** \n 2. if the incoming `msg` contains `msg.<paramName>:tempvalue`\n then `tempvalue` is temporarily assigned to parameter (optional).\n\n 3. the dynamic value can be obtained inside the subflow using `flow.get(<paramName>)` (instead of `env.get(<paramName>`), still valid for static parameters).\n \n## use\n In your subflow:\n 1. Put a 'late bimding' function node between the msg input and your nodes.\n 2. Update the function code, adding at end one line for any dynamic parameter:\n```` \n _upadateParam(<dynamicName1>); \n _upadateParam(<dynamicName2>); \n```` \n 3. If you are updating an existing subflow, replace all `env.get(<dynamicNameX>` with `flow.get(<dynamicNameX>`.\n\nEnjoy\n",
        "category": "",
        "in": [
            {
                "x": 60,
                "y": 60,
                "wires": [
                    {
                        "id": "323fcee7d2ae40cd"
                    }
                ]
            }
        ],
        "out": [],
        "env": [
            {
                "name": "mypameter",
                "type": "str",
                "value": ""
            }
        ],
        "meta": {},
        "color": "#DDAA99"
    },
    {
        "id": "323fcee7d2ae40cd",
        "type": "function",
        "z": "faaa7cdb933cb272",
        "name": "late binding",
        "func": "// This function updates a parameter value and save it in a flow variable with the same name.\n// The nodes in the subflow, instead of using env.get() must use flow.get().\n// Call _upadateParam(<parameter_name>) for any parameter thath requires late or runtime binding.\n\nfunction _upadateParam(_pname){\n var _xvalue = env.get(_pname);\n if (_xvalue){\n _xvalue = _xvalue.toString().trim();\n if (_xvalue.startsWith('global.'))\n _xvalue = global.get(_xvalue.substring(7));\n else if(_xvalue.startsWith('flow.'))\n _xvalue = flow.get(\"$parent.\"+ _xvalue.substring(5));\n else if(_xvalue.startsWith('msg.'))\n _xvalue = msg[_xvalue.substring(4)];\n else _xvalue = env.get(_pname);\n }\n// optional: to set the parameter dynamically with a message property, same name\n if(msg[_pname])\n _xvalue = msg[_pname];\n \n// save actual value in the (sub)flow context \n flow.set(_pname, _xvalue);\n }\n \n// here CUSTOMIZE: \n_upadateParam(\"myparameter\") ; // the parameter name\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 190,
        "y": 60,
        "wires": [
            [
                "a81b3db0f226a117"
            ]
        ]
    },
    {
        "id": "90e9b0da29850be2",
        "type": "comment",
        "z": "faaa7cdb933cb272",
        "name": "here more subflow nodes",
        "info": "",
        "x": 410,
        "y": 120,
        "wires": []
    },
    {
        "id": "a81b3db0f226a117",
        "type": "debug",
        "z": "faaa7cdb933cb272",
        "name": "only for test",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 390,
        "y": 60,
        "wires": []
    }
]

`````
