Not ordinary using function node and flow.set/get

Hi, there.

Did you using all function node features?
Today I found solution how to make function node send specified message without any input msg.

Just try this:

[{"id":"9c663e52.a1985","type":"function","z":"696d2510.1151ac","name":"Create object","func":"var test_obj = {\n    SendMsg: function( data ) {\n        node.send( { payload: data } );\n    }\n}\n\nflow.set( \"test_obj\", test_obj );","outputs":1,"noerr":0,"x":450,"y":120,"wires":[["2c0153c5.7146ac"]]},{"id":"1113bab7.140835","type":"inject","z":"696d2510.1151ac","name":"Init first","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":250,"y":120,"wires":[["9c663e52.a1985"]]},{"id":"3196b4a6.b5439c","type":"inject","z":"696d2510.1151ac","name":"Send msg 1","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":270,"y":160,"wires":[["ffd9247d.e2e218"]]},{"id":"ffd9247d.e2e218","type":"function","z":"696d2510.1151ac","name":"","func":"var test_obj = flow.get( \"test_obj\" );\ntest_obj.SendMsg( \"Hello\" );","outputs":1,"noerr":0,"x":430,"y":160,"wires":[[]]},{"id":"2c0153c5.7146ac","type":"debug","z":"696d2510.1151ac","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":630,"y":120,"wires":[]},{"id":"50297e0d.a10f7","type":"inject","z":"696d2510.1151ac","name":"Send msg 2","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":270,"y":200,"wires":[["bb1fcb91.7c3ed8"]]},{"id":"bb1fcb91.7c3ed8","type":"function","z":"696d2510.1151ac","name":"","func":"var test_obj = flow.get( \"test_obj\" );\ntest_obj.SendMsg( \"World\" );","outputs":1,"noerr":0,"x":430,"y":200,"wires":[[]]}]

This is bug, or feature? Im newbee in JS scripting, and see this useful.
I want using it in my projects, but I must be shure, this feature will not be depricated in future.

Ordinarily you'd put the data in context and then your second function gets the data and sends it.

What value does putting the whole function into context provide you? If you want to trigger a 'remote' flow (ie a flow you are not wired directly to), then use Link nodes as they don't require you to inject anything into context at the start.

Certainly putting Functions into context is a pattern of usage that exists (as long as you don't have persistent context enabled - Functions cannot be persisted). More typically we see it used to put shared utility functions into context that can be reused by multiple function nodes.

We're not going to actively block JavaScript functions being out into context, but I would ask you make really sure it's the right approach for your particular scenario as there are usually better alternatives.

Ordinarily you'd put the data in context and then your second function gets the data and sends it.

Maybe i don't understand right. How second function can be triggered to check updated data in context? Except it will updating by timer or input wire.

I'm creating context objects with their own methods and properties. It allows to share and reuse methods without new defining its in any function block, where I need it. This avoids code duplication, which is good practice.

For example, we have this code:

var x_utils = flow.get( "x_utils" );
if( msg.data.length > 64 ) {
    x_utils.UpdateNodeStatus( "Data too long" );
    return;
}
let values = [];
// handle msd.data --> values[]
x_utils.UpdateNodeStatus( "Data handled" );
node.send({payload: values});

There are two branches - UpdateNodeStatus() and node.send(). In ordinary case, if I want to separate function output, I using multiple function node outputs, and code like this:

if( msg.data.length > 64 ) {
    node.send( [ null, { payload: "Data too long" } ] );
    return;
}
let values = [];
// handle msd.data --> values[]
node.send( [ null, { payload: "Data handled" } ] );
node.send( [ { payload: values }, null ] );

If function node has more than 2 outputs, its goes to very uncomfortable to write and read code.

Alternatively we can add "branch" property in msg, and then using "switch" node to separate branches:

if( msg.data.length > 64 ) {
    node.send( { branch: "status", payload: "Data too long" } );
    return;
}
let values = [];
// handle msd.data --> values[]
node.send( { branch: "status", payload: "Data handled" } );
node.send( { branch: "data", payload: values } );

Is there any other ways?

This category is really meant for competed projects not general or development questions

There is no guarantee that context storage will allow functions to be stored. Indeed, as Nick as stated, if you switch from the default memory context, you cannot do so. The only accepted way for adding functions to context is via settings.js which lets you attach any JavaScript object to the global memory context store. You can use this. as many of us do, to share functions or classes. I commonly share lodash for example.

If you don't wish to keep amending settings.js when you add a new shared function, you can utilise node.js's module system and require an external file. Just note that functions loaded this way do require a restart of Node-RED when changes are made. If you are rapidly prototyping and need this, I recommend using nodemon or pm2 configured to look for changes in your files so that Node-RED is automatically restarted.

Another way to "share" functions is to put them in their own function node in a sub-flow. Not quite as efficient in terms of performance though that is rarely an issue, but easy to manage.

This topic was automatically closed after 60 days. New replies are no longer allowed.