Change node enhancements

The change node has become the tool I often reach for instead of the function node, but it has a few limitations that seem arbitrary.

First, it can read and write the flow and global contexts but not the local context. This would be useful in the same way as in the function node, so I wonder if there are technical reasons why it would not be possible.

Also, but less important, it would be nice if the change node could call node.log, node.warn, node.error, and node.status (and display its status). I sometimes write one or two lines of JavaScript in a function node, just to get an error or status message displayed.

I realize that the original purpose of the change node was simply to manipulate message properties, but now that it can handle simple conditionals in JSONata and regex, it make sense to use the function node only for more complex logic. In a way, the function node also just manipulates message and context properties but with the full capabilities of JS. Some new users of Node-RED seem to find learning JS an obstacle, so giving a bit more power to the change node might smooth their progress.

2 Likes

Mike, funny you should ask this...

I just recently received an email that my PR for accessing local context in a change node (and JSONata) has been targeted for the new dev branch. So it looks like it will be available in an upcoming release.

1 Like

Happily agree with your first point and it looks like that will get sorted.

I get why you are asking for this but that needs to be balanced against the principle that a node should do one thing and do it well. The change node changes things.

What might help would be some explanation of a use-case. How would you expect this to look and work if it were implemented?

1 Like

For logging perhaps the debug node could be enhanced with warn/error ?
I often set my logging message in a change node in msg.log with a debug node set to handle msg.log.

like - https://trello.com/c/AG9C90iy/124-debug-node-add-loglevels :slight_smile:

2 Likes

@shrickus Thanks! You not only had the idea but did the work. You even picked up the corresponding change in JSONata. Well done.

@TotallyInformation These two flows are trivial cases where a change node could easily replace a function if it had access to node.status.

[{"id":"8f20d429.7359b","type":"inject","z":"7925ee05.cefd08","name":"good request","topic":"","payload":"https://www.npmjs.com/package/node-red","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":130,"y":200,"wires":[["fef21224.b26d58"]]},{"id":"8d21f60d.734478","type":"http request","z":"7925ee05.cefd08","name":"","method":"GET","ret":"txt","url":"","tls":"","x":470,"y":220,"wires":[["7fc9ce30.aaf89"]]},{"id":"fef21224.b26d58","type":"change","z":"7925ee05.cefd08","name":"","rules":[{"t":"set","p":"url","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":220,"wires":[["8d21f60d.734478"]]},{"id":"4aa8135e.14befc","type":"inject","z":"7925ee05.cefd08","name":"bad request","topic":"","payload":"https://www.npmjs.com/package/node-blue","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":"","x":130,"y":240,"wires":[["fef21224.b26d58"]]},{"id":"7fc9ce30.aaf89","type":"function","z":"7925ee05.cefd08","name":"status","func":"node.status({shape:'dot',text:msg.statusCode,fill:msg.statusCode == 200 ? 'green' : 'red'});\nmsg.status = (msg.statusCode == 200) ? 'nr-dashboard-ok' : 'nr-dashboard-error';\nreturn msg;","outputs":1,"noerr":0,"x":610,"y":220,"wires":[["1ab61b19.a324b5"]]},{"id":"1ab61b19.a324b5","type":"ui_text","z":"7925ee05.cefd08","group":"172cda24.4d5896","order":1,"width":"6","height":"1","name":"","label":"Server","format":"<i class=\"fa fa-circle fa-1x {{msg.status}}\"></i>","layout":"row-left","x":730,"y":220,"wires":[]},{"id":"28159810.7a6338","type":"exec","z":"7925ee05.cefd08","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"","x":290,"y":320,"wires":[["d0029500.0ab12"],[],[]]},{"id":"28be5199.02b4de","type":"inject","z":"7925ee05.cefd08","name":"good command","topic":"","payload":"cd /usr","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":300,"wires":[["28159810.7a6338"]]},{"id":"5212b0e4.e9e73","type":"inject","z":"7925ee05.cefd08","name":"bad command","topic":"","payload":"cd /foo","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":340,"wires":[["28159810.7a6338"]]},{"id":"d0029500.0ab12","type":"function","z":"7925ee05.cefd08","name":"rc","func":"node.status({shape:'dot',text:msg.rc.message,fill:msg.rc.code === 0 ? 'green' : 'red'});\nmsg.status = (msg.rc.code === 0) ? 'nr-dashboard-ok' : 'nr-dashboard-error';\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":320,"wires":[["1fc2a24b.d9d04e"]]},{"id":"1fc2a24b.d9d04e","type":"ui_text","z":"7925ee05.cefd08","group":"172cda24.4d5896","order":2,"width":"6","height":"1","name":"","label":"OS","format":"<i class=\"fa fa-circle fa-1x {{msg.status}}\"></i> {{msg.rc.message}}","layout":"row-left","x":550,"y":320,"wires":[]},{"id":"172cda24.4d5896","type":"ui_group","z":"","name":"","tab":"8ab9a99d.fc461","disp":true,"width":"6","collapse":false},{"id":"8ab9a99d.fc461","type":"ui_tab","z":"7925ee05.cefd08","name":"Server","icon":"dashboard","order":4}]

Better examples would use node.log or node.warn, but the ones in my code are difficult to simplify. You get the idea, and as I said, it's not a big deal. To be honest, I raised the question of node.status in an earlier discussion and ended by agreeing with Dave that the function node was the right way to go.