# HowTo define and use global utillity function in V3.x and higher

**URL:** https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054
**Category:** General
**Tags:** function-node
**Created:** [5 September 2023 13:56 UTC](https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054 "2023-09-05T13:56:49Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![Moosbueffel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/moosbueffel/32/36732_2.png) [@Moosbueffel](https://discourse.nodered.org/u/Moosbueffel)
#### Post date: [5 September 2023 13:56 UTC](https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054/1 "2023-09-05T13:56:49Z")

</div>

I found a [post](https://discourse.nodered.org/t/global-function-for-multiple-function-nodes/42394) here for this question, but it is 2 years ago and there were remarks to the solution, that it is not good and perhaps not usable in future. Also I found a solution in [stackoverflow](https://stackoverflow.com/questions/49006213/how-to-write-multiple-reusable-global-functions-in-nodered), but also more a workaround.

So my question is, how to do this in Node-Red V3 in an easy way. I did some programming, but don't be perfect. So please explain it step by step and perhaps with an example.

Is there a plan to integrate it in the user interface? I think nearly everybody will need something like this.

---

<div class="post-metadata">

### Author: ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)
#### Post date: [5 September 2023 14:04 UTC](https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054/2 "2023-09-05T14:04:00Z")

</div>

Why do you want a globally defined function?

The visual equivalent is the `link-call` node.

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/b/d/bd46db4aa1ef829ce69e55d8bc3fd80fba4fdacd.png)

Demo Flow...

```auto
[{"id":"e8031839f82a4fac","type":"link in","z":"65b88f90c5129bc8","name":"mult * 10","links":[],"x":255,"y":600,"wires":[["e7680a651c3e6672"]]},{"id":"9f01e7a2880c059b","type":"link out","z":"65b88f90c5129bc8","name":"link out 1","mode":"return","links":[],"x":465,"y":600,"wires":[]},{"id":"e7680a651c3e6672","type":"function","z":"65b88f90c5129bc8","name":"mult * 10","func":"msg.payload = msg.payload * 10\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":600,"wires":[["9f01e7a2880c059b"]]},{"id":"342498501c490f97","type":"inject","z":"65b88f90c5129bc8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2","payloadType":"num","x":180,"y":480,"wires":[["29aa1920221cce50"]]},{"id":"29aa1920221cce50","type":"link call","z":"65b88f90c5129bc8","name":"","links":["e8031839f82a4fac"],"linkType":"static","timeout":"30","x":340,"y":480,"wires":[["cea61592b52d6752"]]},{"id":"cea61592b52d6752","type":"debug","z":"65b88f90c5129bc8","name":"expect 20","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":530,"y":480,"wires":[]},{"id":"967c68d72db42af5","type":"link call","z":"65b88f90c5129bc8","name":"","links":["e8031839f82a4fac"],"linkType":"static","timeout":"30","x":340,"y":520,"wires":[["1153c860b9b37a59"]]},{"id":"fe1d85d82704835b","type":"inject","z":"65b88f90c5129bc8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"4","payloadType":"num","x":180,"y":520,"wires":[["967c68d72db42af5"]]},{"id":"1153c860b9b37a59","type":"debug","z":"65b88f90c5129bc8","name":"expect 40","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":530,"y":520,"wires":[]}]

```

---

<div class="post-metadata">

### Author: ![Buckskin](https://avatars.discourse-cdn.com/v4/letter/b/b9e5f3/32.png) [@Buckskin](https://discourse.nodered.org/u/Buckskin)
#### Post date: [5 September 2023 21:07 UTC](https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054/3 "2023-09-05T21:07:59Z")

</div>

I do not think there are any better ways than those mentioned but this is a way that I got round the problem (not my original idea) if looking to store more than 1 function.

Use a `function node` to keep the required functions, with an `inject node` set to inject at startup

An example

```auto
const utility = (function () {
    'use strict';

    /*
    * Functions Available
    *
    * scale,
    * ordinal,
    * isString,

    *
    */

    /**
    * 
    * @param {number} number Number of range to scale
    * @param {number} inMin Minimum of range to scale
    * @param {number} inMax Maximum of range to scale
    * @param {number} outMin Minimum of range to be scaled to
    * @param {number} outMax Maximum of range to be scaled to
    * 
    * Example scale(20, 0, 100, 15, 30) Results in a number in range [0 - 100] being ouput as a number in range [15 - 30]
    * 
    */

    function scale (number, inMin, inMax, outMin, outMax) {
        return (number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin

    } // End Function scale()

    /**
    * Description   
    * 
    * @param {string | number} number - The item to check
    * @param {boolean} inclusive - Append ordinal to number if true. Defaults to true
    * 
    * @return {string} - The ordinal suffix for provided number. If inclusive is true returns number + ordinal
    *
    * @Example let monthDay = ordinal(21, true); => 21st
    */

    function ordinal(number, inclusive = true) {
        let x = Number(number)
        const ORDINAL = ["th", "st", "nd", "rd"][(x = ~~(x < 0 ? -x : x) % 100) > 10 && x < 14 || (x %= 10) > 3 ? 0 : x]

        return (inclusive) ? number + ORDINAL : ORDINAL

    } // End Function ordinal()

    /**
    * Description Determines whether or not supplied argument is of type 'string'.
    * 
    * @param {*} strValue - The argument to check.
    * 
    * @return {boolean} - True if the argument is of type 'string', otherwise false.
    */

    function isString(strValue) {
        return ((typeof strValue === 'string') || (strValue instanceof String))

    } // End Function isString()

    return {

        scale,
        ordinal,
        isString,

    }

}())

global.set('utility', utility, 'file')

```

Functions are used by calling;

```auto
const utility = global.get('utility', 'file')

let possibleString = 'jdf'
let isString = utility.isString(possibleString)

```

Simple example flow

```auto
[{"id":"6d067867ce6a2d06","type":"function","z":"8428164b1645b4b8","name":"Library","func":"const utility = (function () {\n 'use strict';\n\n /*\n * Functions Available\n *\n * scale,\n * ordinal,\n * isString,\n\n *\n */\n\n /**\n * \n * @param {number} number Number of range to scale\n * @param {number} inMin Minimum of range to scale\n * @param {number} inMax Maximum of range to scale\n * @param {number} outMin Minimum of range to be scaled to\n * @param {number} outMax Maximum of range to be scaled to\n * \n * Example scale(20, 0, 100, 15, 30) Results in a number in range [0 - 100] being ouput as a number in range [15 - 30]\n * \n */\n\n function scale(number, inMin, inMax, outMin, outMax) {\n return (number - inMin) * (outMax - outMin) / (inMax - inMin) + outMin\n\n } // End Function scale()\n\n\n\n /**\n * Description \n * \n * @param {string | number} number - The item to check\n * @param {boolean} inclusive - Append ordinal to number if true. Defaults to true\n * \n * @return {string} - The ordinal suffix for provided number. If inclusive is true returns number + ordinal\n *\n * @Example let monthDay = ordinal(21, true); => 21st\n */\n\n function ordinal(number, inclusive = true) {\n let x = Number(number)\n const ORDINAL = [\"th\", \"st\", \"nd\", \"rd\"][(x = ~~(x < 0 ? -x : x) % 100) > 10 && x < 14 || (x %= 10) > 3 ? 0 : x]\n\n return (inclusive) ? number + ORDINAL : ORDINAL\n\n } // End Function ordinal()\n\n\n /**\n * Description Determines whether or not supplied argument is of type 'string'.\n * \n * @param {*} strValue - The argument to check.\n * \n * @return {boolean} - True if the argument is of type 'string', otherwise false.\n */\n\n function isString(strValue) {\n return ((typeof strValue === 'string') || (strValue instanceof String))\n\n } // End Function isString()\n\n\n return {\n\n scale,\n ordinal,\n isString,\n\n }\n\n}())\n\nglobal.set('utility', utility, 'file')","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":1180,"wires":[["42d772a9a7b90346"]]},{"id":"79fbe6817cbb7300","type":"function","z":"8428164b1645b4b8","name":"Test Library","func":"const utility = global.get('utility', 'file')\n\nfunction isString(strValue) {\n return ((typeof strValue === 'string') || (strValue instanceof String))\n}\n\nlet possibleString = 'jdf'\nlet ifString = utility.isString(possibleString)\n\nmsg.payload = ifString\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":1240,"wires":[["4797811e083e1e8b"]]},{"id":"9341e34e33086a04","type":"inject","z":"8428164b1645b4b8","name":"Startup","props":[],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","x":120,"y":1180,"wires":[["6d067867ce6a2d06"]]},{"id":"42d772a9a7b90346","type":"debug","z":"8428164b1645b4b8","name":"Library Out","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":550,"y":1180,"wires":[]},{"id":"2859e1c24558295a","type":"inject","z":"8428164b1645b4b8","name":"Trigger Test","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":1240,"wires":[["79fbe6817cbb7300"]]},{"id":"4797811e083e1e8b","type":"debug","z":"8428164b1645b4b8","name":"Test Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":1240,"wires":[]}]

```

---

<div class="post-metadata">

### Author: ![Moosbueffel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/moosbueffel/32/36732_2.png) [@Moosbueffel](https://discourse.nodered.org/u/Moosbueffel)
#### Post date: [6 September 2023 14:49 UTC](https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054/4 "2023-09-06T14:49:43Z")

</div>

Thanks @Steve-Mcl ! I saw the link-call node, but doesn't understand it. Now it's clear. A good choice to use a function-node several times. I will store it in my memory :).

The second one from @Buckskin is what I need at the moment. A reusable function inside my function node. This is more - like you show - for a function library. I got the warning:  
("Unbekannter Kontextspeicher 'file ' angegeben. Standard-Kontextspeicher wird verwendet.")  
Unknown contextmemory 'file'. Default context memory will be used

But I think it is something to do in the settings, so the context-memory is stored in a file and not in the RAM? I have to look for.

Also special thanks for the examples. I tried both and the understanding is much more clear than only a descripton.

I think I can only mark **one** as a solution, so I don't mark any because both are valid.

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)
#### Post date: [5 November 2023 14:50 UTC](https://discourse.nodered.org/t/howto-define-and-use-global-utillity-function-in-v3-x-and-higher/81054/5 "2023-11-05T14:50:02Z")

</div>

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