Using simpler globar variables `RED.f.myVar`

I'm currently a bit frustrated why it has to be sooooo complicated to use always these flow.get() .set() methods to simply store a variable in memory?

I know I can make my own "utility functions", but still I have to define that in every each function to be able to access.

So the million $ question:

  • Why not pre-define two ?
  1. RED.global = RED.g
  2. RED.flow = RED.f

(RED.g and RED.f are short-form aliases.)
So anybody could simply use them everywhere just list this:

RED.f.myCounter += RED.g.myArray[0].value;

and that's all!
And for everything else (like context store on HDD, etc) everyone could still use the old methods.

PS: First I've tried to use simply flow.myVar, but it did not work.

Because we want a single api for context so the user doesn’t need to have to think/know about where they want to store things, and that can be changed (in settings.js) at any time without breaking the flow.

Also flow.myvar (and global.myvar ) - which are memory only -,should still work in function nodes but won’t show up in the context sidebar or other nodes

Do I get my million $ ?

Maybe I'm being a bit thick but surely it should be written as...

RED.g = RED.global;
RED.f = RED.flow;

Complex? const myvar = flow.get('myvar') is complex? Much more complex than const myvar = flow.myvar?

You could, of course, use change nodes. One before your function node to get the data and add it to an incoming message and one after to write the update data back. Though that seems a lot more complex.

You could always also set a couple of snippets of code into the library for easy access.

Isn't flow.set() get() standard JS?

I am not sure about lower (/higher) level programming, but I for one, would really like to keep my JS standard and not wonder what RED.g RED,f are in an example flow.

Maybe I am missing the point?

Agree. If anything const fg = flow.get and similar if you are using it a lot in a function node. And if you are using these things a "lot" in a function node, you may want to take a step back for a minute and think about whether you are doing things the best way.

Yes, it is.

let myvar = flow.get('mySpecialVar');
myvar = 5;
flow.set('mySpecalVar', myvar); // error already happend

With my idea:

RED.f.mySpecialVar = 5;

Yes, it looks nicer :wink:
They would work as alias, so both could be used the same way.
If anyone can thing of an even shorted form, that can be easily memorised, share it here!
eg. NRV = NodeRed Variable

Just to point out that if mySpecialVar is an object, then you do not need to use flow.set() to update key values stored in it.

This is valid in a function node, and updates the counter stored in flow context.

node.warn(flow.get('RED').counter ++)

[{"id":"2735b59096ed3aa4","type":"function","z":"790f697c022493af","name":"function 19","func":"node.warn(flow.get('RED').counter ++)","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":240,"wires":[[]]},{"id":"89a8cf55016f77c4","type":"inject","z":"790f697c022493af","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1080,"y":240,"wires":[["2735b59096ed3aa4"]]},{"id":"b410e9a77bfee940","type":"inject","z":"790f697c022493af","name":"init","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1070,"y":80,"wires":[["09fad47bf63d1869"]]},{"id":"09fad47bf63d1869","type":"change","z":"790f697c022493af","name":"Create flow.myobject","rules":[{"t":"set","p":"RED","pt":"flow","to":"{\"counter\":0}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1260,"y":80,"wires":[[]]}]

But only for in-memory context stores. If you're enabled File-based persistence, then not calling set will mean the value doesn't get saved as you might expect and will revert if you restart NR.

Nope! That is incorrect. Partially anyway. While that does work for in-memory variables right now, it might not work for other variable libraries and might not work in the future anyway. It is dangerous and fragile.

Best to think of context variables as an API with access only via get and set. Your future self will likely thank you greatly. :smiley:

If you really wanted to simplify the coding, we would need the core to replace the current libraries with a JavaScript proxy. That would allow the get/set to be hidden within the proxy.

@jbudd Wow! Actually this is a great idea! :+1:

Not perfect, but +1 step easier. (No need to use flow.set(), a few lines less of coding).
I've never thought that a flaw of object-deep-copy problem can be a benefit too!

Basically we are:

  1. loading only the reference (pointer) of the object at the beginning,
  2. and modifying only the sub-values of it,
  3. this way we do not have to "save it" back.
  • Right?

This is easierst method, how my idea would be doable programmatically inside the core.
So basically +2 lines in the source would allow to everyone to use global + flow variables without get() set().

It does not need to begin with RED. . Could be _GV for globalValues, _FV for flowValues.


What I still not understand is:

  • if it is enough to load=get() the object reference point,
  • and if I put the declaration part of it to the "OnStart" tab of the node,
    let c = flow.get('RED');
  • why is it not working than? node.warn(c.counter ++);
[{"id":"9147025004dc8078","type":"function","z":"163bd37ac7d1c01c","name":"function 1","func":"node.warn(c.counter ++);","outputs":1,"timeout":0,"noerr":0,"initialize":"let c = flow.get('RED');","finalize":"","libs":[],"x":360,"y":280,"wires":[[]]},{"id":"9ec33294fae26402","type":"inject","z":"163bd37ac7d1c01c","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":180,"y":280,"wires":[["9147025004dc8078"]]}]

@jbudd Note:

RED is a global reserved word in NR. We should not use it in examples as sub-variables, because it may confuse users visiting later this topic.


@knolleary Yes, thanks, we know that! I've explicitly said at the beginning:

  • Store in MEMORY ONLY.
  • Only as long we restart the flow / NR.
  • No need to write temporary variables to disc!

I know you know and I know you said it. The dangerous part comes when others read this thread and don't appreciate that subtle yet very important reason for set being used.

You are free to do whatever works for you.

Point taken, thanks.

Actually I would say that updating an object, in context or anywhere else, without explicitly saving it is likely to confuse anyone apart from the original coder who has to maintain the code, and therefore we should not do it.

If I were to implement a counter in context I would use

const iterationCounter = context.get('iterationCounter') +1 || 1
context.set('iterationCounter', iterationCounter)

...
node.warn("You have run this " + iterationCounter + " times")

// And if I want to use the counter later in the flow, attach it to the message
msg.iterationCounter = iterationCounter

Yes, thanks, but I'm not sure where to place it into Node-red core code,
and even if I would find a good place for it in the source,
I'm not sure You guys would accept my commit?

That's why I'd like to discuss it first here.
(But it seems everyone is against my idea to simplify usage of global temp.variables.)

OFF

I still remember how much time it took me to learn about context variables at the first time, when I've started to use NodeRed years ago.
Also there are many many topics asking about the same simple question:

  • how to use global variables that can be passed on to other nodes,
  • which are not connected to each other
  • and would confuse everyone if they would be!

Yes, that's the default way, if it is possible.
But life is more complicated than 1 simple line of flow ...
(for example: keeping count+lastAccess of all MQTT clients, who connected before.)

Can somebody answer me that please?

Maybe I've missed your proposal. You want RED.f and RED.g to exist as shorthands for flow and global ? Or something else?

No, not shorthands.
Yes, something else:

  • pre-existing global variable containers.

RED.g = {}; would be created when NR starts.
RED.f = {}; would be created for each flow. (Separately).

This way new users (and we) had two, easy-useable variables-trunc defined, which can be used for any sub-variable.
How you name it:
RED.f or _FV or flowVar, I do not care, as long it is documented here and here.

I have found the problem:

Using let ... or var ... is bad at "On Start" tab !
This one works:

c = flow.get('RED'); // good :-)

But WHY ?
I've thought the 'On Start' tab context is the same / parent of "on Message"...

We aren't going to introduce another way to use context that doesn't quite work the same as other ways of using context.

If you really want to, you can just use flow.myVariable = "hello" - no need for us to introduce more globals.