[behavior] Activating a function from the previous function node

I was testing something, and i see this behavior with node functions and the node-red.

I have created two function nodes:
-the first one creates a function with node.send ()
-the second calls this function
-I get an error, but the function is performed in the previous node

[{"id":"3cd6fd57.dbf502","type":"inject","z":"444df3bd.bed4dc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":140,"wires":[["f740d75f.c6de88"]]},{"id":"f740d75f.c6de88","type":"function","z":"444df3bd.bed4dc","name":"set function in msg","func":"msg.functions={\n    foo:function(){\n        node.send({\"test\":\"test\"})\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":290,"y":140,"wires":[["d19ea6d5.e69e48","8deb8124.fb84b"]]},{"id":"513f0336.015a8c","type":"debug","z":"444df3bd.bed4dc","name":"out 1  :D","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":720,"y":140,"wires":[]},{"id":"d19ea6d5.e69e48","type":"function","z":"444df3bd.bed4dc","name":"apply func","func":"msg.functions.foo()\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":510,"y":140,"wires":[["513f0336.015a8c"]]},{"id":"8deb8124.fb84b","type":"debug","z":"444df3bd.bed4dc","name":"Why im here?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":520,"y":200,"wires":[]}]

I am doing something wrong?
why does this behave like this?


This is not a big problem, it is just that I do not understand the behavior

What happens is it works - then the 1st functions .foo() method node.sends a message containing only {"test":"test"} to the 2nd function (which does not contain .functions) - hence the error. If you test for the presence of msg.functions in your 2nd function it wont happen.

Add node.warn(["msg in function 1", msg]) and node.warn(["msg in function 2", msg]) to your functions this should be clearer

ok, I understood why this gave me an error.
The behavior that I thought this would have is that when activating the function in the second node, it would act on the second, not the first.
or so I think
it may help me for some recursive tasks ,since I could loop with this

[{"id":"3cd6fd57.dbf502","type":"inject","z":"444df3bd.bed4dc","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":680,"y":120,"wires":[["f740d75f.c6de88"]]},{"id":"f740d75f.c6de88","type":"function","z":"444df3bd.bed4dc","name":"set function in msg","func":"msg.functions={\n    foo:function(){ \n        node.send({\n            \"test\":\"test\",\n            functions:{\n                foo:function(){\n                    node.warn(\"end\")\n                }\n            }\n        })\n    }\n}\nnode.warn([\"msg in function 1\", msg])\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":860,"y":120,"wires":[["d19ea6d5.e69e48","8deb8124.fb84b"]]},{"id":"513f0336.015a8c","type":"debug","z":"444df3bd.bed4dc","name":"out 1  :D","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1290,"y":120,"wires":[]},{"id":"d19ea6d5.e69e48","type":"function","z":"444df3bd.bed4dc","name":"apply func","func":"node.warn([\"msg in function 2\", msg])\nmsg.functions.foo()\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1080,"y":120,"wires":[["513f0336.015a8c"]]},{"id":"8deb8124.fb84b","type":"debug","z":"444df3bd.bed4dc","name":"Why im here?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1090,"y":180,"wires":[]}]

thanks for answering

No, a function operates where you design it unless you pass in some context to operate on.

There are a few ways (binding / apply etc) but here are 2 of the simpler ways...

First one - you pass in the node context to operate on...

// function 1
msg.functions={
    foo:function(n){
        n.send({"desc":"foo"})
    },
    bar:function(n){ 
        n.send({"desc":"bar"})
    }
}

// function 2
msg.functions.foo(node)
msg.functions.bar(node)

Another way is a function factory...

// function 1
msg.functionFactory=function(_node){
    var node = _node;
    return {
        foo:function(){ node.send({"desc":"foo"}) },
        bar:function(){ node.send({"desc":"bar"}) }
    }
}

// function 2
var ff = new msg.functionFactory(node);
ff.foo()
ff.bar()

demo flow...

[{"id":"3cd6fd57.dbf502","type":"inject","z":"336fad55.d74c02","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":844,"y":544,"wires":[["f740d75f.c6de88"]]},{"id":"f740d75f.c6de88","type":"function","z":"336fad55.d74c02","name":"passing context","func":"msg.functions={\n    foo:function(n){\n        n.send({\"desc\":\"foo\"})\n    },\n    bar:function(n){ \n        n.send({\"desc\":\"bar\"})\n    }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1014,"y":544,"wires":[["d19ea6d5.e69e48","8deb8124.fb84b"]]},{"id":"513f0336.015a8c","type":"debug","z":"336fad55.d74c02","name":"out 1  :D","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1454,"y":544,"wires":[]},{"id":"d19ea6d5.e69e48","type":"function","z":"336fad55.d74c02","name":"apply func","func":"msg.functions.foo(node)\nmsg.functions.bar(node)\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1244,"y":544,"wires":[["513f0336.015a8c"]]},{"id":"8deb8124.fb84b","type":"debug","z":"336fad55.d74c02","name":"Why im here?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1254,"y":604,"wires":[]},{"id":"f7bdf46e.066cb8","type":"inject","z":"336fad55.d74c02","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":844,"y":656,"wires":[["2fb421b0.9c836e"]]},{"id":"2fb421b0.9c836e","type":"function","z":"336fad55.d74c02","name":"functionFactory","func":"msg.functionFactory=function(_node){\n    var node = _node;\n    return {\n        foo:function(){ node.send({\"desc\":\"foo\"}) },\n        bar:function(){ node.send({\"desc\":\"bar\"}) }\n    }\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1014,"y":656,"wires":[["ceed402d.fb068","dfe7dc7d.9db2e"]]},{"id":"ceed402d.fb068","type":"function","z":"336fad55.d74c02","name":"apply func","func":"var ff = new msg.functionFactory(node);\nff.foo()\nff.bar()","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1244,"y":656,"wires":[["a763a36d.2b0b7"]]},{"id":"dfe7dc7d.9db2e","type":"debug","z":"336fad55.d74c02","name":"Why im here?","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1254,"y":716,"wires":[]},{"id":"a763a36d.2b0b7","type":"debug","z":"336fad55.d74c02","name":"out 1  :D","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1454,"y":656,"wires":[]}]

This will be fine most of the time - at some point in the future if you start to use messaging plugins this may not work as functions are not generally serialisable.

@Nxito - what Dave said :slight_smile: (I neglected to include the caveat).

The better way (for now) would probably be to include your functions via settings.js

well - it's only a small caveat and unlikely for most users - but do remember it if it stops working in the future for some "random" reason.

Thank you very much for the warning, I will keep it in mind :smile:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.