Use function multiple times

#1

Hello,

Is it possible to use a function that i created multiple times on different places?
Or do i have to copy them to all instances that i want to use?

already thanks!

#2

Easiest is the select the node on the screen and then use the standard copy and paste shortcuts

#3

One approach would be to use the global.set() with the memory module.

  1. store your function in a global variable:
global.set('sum', function(a, b) {
    return a + b;
}, 'memoryOnly');
  1. use your function:
msg.payload = global.get('sum', 'memoryOnly')(2, 3);

return msg;

Note: you need this setting in the settings.js:

    contextStorage: {
        default: {
	          module:"localfilesystem"
        },
        memoryOnly: {
            module: "memory"
        }
    },

Flow:

[{"id":"4ac1d184.c4df1","type":"inject","z":"66646ca8.e97654","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":2960,"wires":[["f3f7db1.61ac128"]]},{"id":"f3f7db1.61ac128","type":"function","z":"66646ca8.e97654","name":"","func":"global.set('sum', function(a, b) {\n    return a + b;\n}, 'memoryOnly');","outputs":1,"noerr":0,"x":340,"y":2960,"wires":[[]]},{"id":"1b0cf5f7.27cc2a","type":"function","z":"66646ca8.e97654","name":"","func":"msg.payload = global.get('sum', 'memoryOnly')(2, 3);\n\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":3020,"wires":[["da372639.45dec8"]]},{"id":"ddabba53.8d96e8","type":"inject","z":"66646ca8.e97654","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":3020,"wires":[["1b0cf5f7.27cc2a"]]},{"id":"da372639.45dec8","type":"debug","z":"66646ca8.e97654","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":490,"y":3020,"wires":[]}]
1 Like
Calling a function within a function
#4

Hi @KoenH

A third approach (and the one I think is the easiest to manage) is to put your Function node inside a Subflow. That gives you a new node in the palette you can add wherever you want it in your flows. When you edit the subflow template, it automatically updates all of the individual instances you've added.

The Subflow technique is useful wherever you have a node (or group of nodes) that you want to reuse in your flows and don't want to copy/paste them around (as you lose the ability to keep them in sync with edits).

To do this, select your Function node then select the 'Subflows->Selection To Subflow' menu option. That will move the Function node to a subflow, adding a new node to the 'Subflow' section of the palette. To edit the subflow later, you can either double-click it in the palette, or click the 'edit subflow template' button in the node's edit dialog.


@cflurin It's worth mentioning that the technique you suggest doesn't strictly require editing the settings file. That's only if they want to enable the filesystem storage as well, so would need to make those changes to give them a memory-context and a filesystem storage. Without those changes, the context will be in memory so would work as-is. But it also requires the function to get into context in the first place - which adds some added complexity to the resulting flow. Ultimately it's personal choice which approach, but this is pretty much exactly what subflows were designed for.

1 Like
#5

I would agree with @knolleary that this is exactly what a subflow is for.

Copying function nodes is a nightmare for later support - if you have to change something you now have many places to change it.

Another alternative would be to use link nodes to direct flows to the function but that would only be useful if the output is common. Subflows are the way.

#6

The subflow is really useful and I use it often.

In this case I thought @KoenH would need the function as a sort of util function to integrate in different function nodes but may be it's a misunderstanding.

@knolleary: I know that the context default use the memory module but I think defending programming would help avoiding issues in the future in the case a user starts using contextStorage later.

#7

Thanks a lot!
i will play a bit around with subflows... didn't thought of it myself...

#8

Subflows never made any sense to me until now. Thanks!

#9

Hello again,

Subflows have great possibility for me, but i also need to set some parameters to the subflow.
As i found, i don't think this is possible at the moment.
Is there a way of doing this?

Although i found this topic:


Does anybody knows when this would be available?

Alraeady thanks.
Koen.

#10

Without knowing the exact use-case it is hard to advise on the best approach. However, there are a couple of obvious ones.

Firstly using a property on the msg's that you pass into the subflow, this is likely to be the best if your "parameters" change by flow or msg.

Secondly, you can use global variables. This is likely to be best if your params changed by some external environmental factor.

#11

This might be a issue when the function is in a sub flow since using a sub flow indicates the function will be used by many other flows and there is a possibility that another flow changes the values or the function changes the value another flow is using. I think passing the values via the msg is a much safer idea.

#12

Not disagreeing but there may be subflows where this is more appropriate, locking the subflow processing based on a single, global parameter. I would imagine that most people would use the msg object though.

#13

I agree, for example I use a subflow called setState. It receives the current values from all devices and stores them into a global object variable global.set('state', state); Because I use contextStorage (default: localfilesystem) the current values are persistent. In my flows I can than use the device current values for example to control the heating.

#14

Subflow instance properties will be available in the very near future. The initial pull-request arrived yesterday, so work is well under way on it.

2 Likes
#15

Another possibility is to export the target function node to the library. I am not sure why this approach has not been mentioned along this thread. Perhaps not very practical to export /import? I find easier to use sub-flows as the function will appear in the node palette (which is not the case for a function saved in a library).

#16

Yes, another valid approach. But, as with copy and paste, it means when you find a bug in the function you need to update each copy manually. The subflow approach means you have one place to edit and all instances are updated.

#17

The reason is that i need to do a small convertion, depending on the msg content.
so in fact, i want to compare the msg with a fixed value. this value is the parameter of the subflow...
So passing via the msg is quite impossible...

#18

Well, that is the use-case I spoke of for using a global variable.

#19

Or maybe a flow variable if you can arrange one "function" per tab - so they can then be different variable values for each instance.

#20

Let's say you want to compare the actual temperature with the target, so you could send a msg like:

msg.payload = {'actual': 19, 'target' 20};

target is your parameter.