# Node object and closure

**URL:** https://discourse.nodered.org/t/node-object-and-closure/52750
**Category:** Developing Nodes
**Created:** [26 October 2021 11:43 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750 "2021-10-26T11:43:25Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)
#### Post date: [26 October 2021 11:43 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/1 "2021-10-26T11:43:25Z")

</div>

I'm trying to refactor my custom node so that some complex domain logic can stay in its own routines.  
However, I found that although the node object can be passed around, some of it's methods don't work as expected.

```auto
module.exports = function(RED) {
    function RunNode_MyTask(config) {
        RED.nodes.createNode(this, config);
        var node = this;
        node.on('input', function(input, send, done) {
            warn_inside(node);
            warn_outside(node);
            warn_closure_outside();
            warn_outside_outside(node);

            function warn_inside(node) {
                node.warn('hello inside!');
            }
        }

        node.on('close', (removed, done) => {
            if (done) { done();}
        });

        function warn_outside(node) {
           node.warn('hello outside!');
        }

        function warn_closure_outside() {
            node.warn('hello closure outside!');
        }
    }
    // <REGISTER_ACTION
    RED.nodes.registerType('My_Node', RunNode_MyTask);
 };

function warn_outside_outside(node) {
    node.warn('hello outside outside!');
}

```

I was expecting `warn_inside()`, `warn_outside()`, `warn_closure_outside()`, and `warn_outside_outside()` to all print to the debug console in Node-Red, but in reality, only `warn_inside()` works as expected.

I'm not totally sure how "this" and closure work, but from VS Code debugger I can see that the node prototype symbol is viewable every step the way, and `.warn()` is clearly defined along the call stack.  
But I just can't see the log in the debug console.

Am I mistaken about the object model so that I'm not supposed to use node objects outside their own event handlers?

BTW, I can't `"use strict'"` inside node functions. Am I not supposed to? I was trying to let the interpreter help me catch problems.

---

<div class="post-metadata">

### Author: ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)
#### Post date: [26 October 2021 13:18 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/2 "2021-10-26T13:18:54Z")

</div>

When you say they don't work as expected, what do you mean? Can you be more specific?

Looking at the code, I don't see any reason for them not to work. `node` is properly in scope - and where you pass it in as an argument, its definitely in scope.

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [26 October 2021 21:28 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/3 "2021-10-26T21:28:28Z")

</div>

> [@kakyoism](#):
>
> I'm not totally sure how "this" and closure work

Not sure about your code but did you see my post on restructuring custom nodes a while back?

I now use a form that, to me at least, makes a lot more sense and enables the logic to be followed more easily while creating a structure that is a lot more modular.

> [@kakyoism](#):
>
> BTW, I can't `"use strict'"` inside node functions. Am I not supposed to? I was trying to let the interpreter help me catch problems.

You generally use that at the module level which forces the whole module to be strict.

---

<div class="post-metadata">

### Author: ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)
#### Post date: [27 October 2021 02:20 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/4 "2021-10-27T02:20:31Z")

</div>

@knolleary

I did indicate my "expectation in my post"

> I was expecting `warn_inside()` , `warn_outside()` , `warn_closure_outside()` , and `warn_outside_outside()` to all print to the debug console in Node-Red,

I got an empty debug console after executing those functions except `warn_inside()`.

---

<div class="post-metadata">

### Author: ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)
#### Post date: [27 October 2021 02:29 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/5 "2021-10-27T02:29:31Z")

</div>

@TotallyInformation Thanks, I did read your code carefully. That was part of my motivation to restructure mine. But along the course, I just don't see why my closures could not "let the node reference pass in fully", neither could my functions use the node input argument to produce the debug print when it comes to `node.warn()` and `node.error()`. I must admit that I'm not yet familiar enough with JS. I'm still reading getify's YDKJY.

But since I don't get any runtime woes about `node.warn()` or `node.error()` inside my closures, I suppose those functions did run.

But it's just that the Node-RED debug console shows nothing, but my `warn_inside()` function shows debug print normally.

---

<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: [27 October 2021 06:15 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/6 "2021-10-27T06:15:32Z")

</div>

Try changing them to console.log & check the console.

---

<div class="post-metadata">

### Author: ![kakyoism](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kakyoism/32/46283_2.png) [@kakyoism](https://discourse.nodered.org/u/kakyoism)
#### Post date: [27 October 2021 09:21 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/7 "2021-10-27T09:21:11Z")

</div>

@Steve-Mcl  
That's what I do right now, but can someone explain to me why this is not working the way I expect?  
I'm really curious. If other side-effects like this exist, I'm really scared to go on refactoring!

Right now we need node.warn()/node.error() to give the end-user useful feedback in the browser, to save the trouble of switching between the Node-RED editor and Terminal/Console/. The target users are not tech-savvy.

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [27 October 2021 09:45 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/8 "2021-10-27T09:45:42Z")

</div>

I think that if you changed the functions to arrow functions, you should be able to use `this` rather than `node`. I can't see why `node` doesn't work though. You could try moving the function definitions above the `node.on` however since though JS is generally forgiving about such things, it _is_ possible that it wants them to be defined first.

A would also recommend using VSCode with ESLINT set up. It helps find issues 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: [27 October 2021 11:40 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/9 "2021-10-27T11:40:33Z")

</div>

> [@kakyoism](#):
>
> That's what I do right now, but can someone explain to me why this is not working the way I expect?

But, is `console.log()` sending the values to console? I wanted to prove that the code lines are being being executed & if they are, then to figure out why `node.warn()` isnt appearing in the browser.

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [27 October 2021 12:08 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/10 "2021-10-27T12:08:14Z")

</div>

> [@kakyoism](#):
>
> That's what I do right now, but can someone explain to me why this is not working the way I expect?  
> I'm really curious. If other side-effects like this exist, I'm really scared to go on refactoring!

You clearly are not using an editor with linting. As soon as I pasted your code from above into my editor it told me that you had a missing `)` at the end of the on input.

After I fixed that, it told me that I was using the functions before they were defined. However, I ignored that and everything worked.

So I would say that your problem lies somewhere else, maybe your HTML file isn't well formed?

Here is an example using my own restructuring that also works - it has the name `jktest3` so you should be able to rename everything to suite:

js file:

```js
/** A simple template for defining custom nodes
 * Destructured to make for easier and more consistent logic.
 */
'use strict'

/** --- Type Defs ---
 * @typedef {import('../typedefs.js').runtimeRED} runtimeRED
 * @typedef {import('../typedefs.js').runtimeNodeConfig} runtimeNodeConfig
 * @typedef {import('../typedefs.js').runtimeNode} runtimeNode
 * typedef {import('../typedefs.js').myNode} myNode
 */

//#region ----- Module level variables ---- //
 
/** Main (module) variables - acts as a configuration object
 * that can easily be passed around.
 */
const mod = {
    /** @type {runtimeRED} Reference to the master RED instance */
    RED: undefined,
    /** @type {string} Custom Node Name - has to match with html file and package.json `red` section */
    nodeName: 'jktest3',

    // Add anything else here that you may wish
    // to access from any function.
    // Having one object also makes it much easier
    // to pass this to external modules as needed.
}

//#endregion ----- Module level variables ---- //

//#region ----- Module-level support functions ----- //

/** 1a) Runs once when Node-RED (re)starts or when the node package is first added */
function moduleSetup() {
    // As a module-level named function, it will inherit `mod` and other module-level variables
    //const RED = mod.RED

    console.log('>>>=[1a]=>>> [moduleSetup] Startng')

    // Do stuff here that only needs doing once
    // Don't forget to push anything that might be needed by other functions and modules
    // into the `mod` variable so that it is easily accessible and can be passed on.
}

/** 3) Run whenever a node instance receives a new input msg
 * NOTE: `this` context is still the parent (nodeInstance).
 * See https://nodered.org/blog/2019/09/20/node-done 
 * @param {object} msg The msg object received.
 * @param {Function} send Per msg send function, node-red v1+
 * @param {Function} done Per msg finish function, node-red v1+
 */
function inputMsgHandler(msg, send, done) {
    // As a module-level named function, it will inherit `mod` and other module-level variables

    // If you need it - or just use mod.RED if you prefer:
    //const RED = mod.RED

    console.log('>>>=[3]=>>> [inputMsgHandler] Startng', msg) //, this)
  
    send(msg)
    done()

}

/** 2) This is run when an actual instance of our node is committed to a flow
 * @param {runtimeNodeConfig} config The Node-RED node instance config object
 */
function nodeInstance(config) {
    // As a module-level named function, it will inherit `mod` and other module-level variables

    // If you need it - which you will here - or just use mod.RED if you prefer:
    const RED = mod.RED

    console.log('>>>=[2]=>>> [nodeInstance] Startng')
    //console.log('>>>=[2a]=>>>', config)

    // Create the node instance - `this` can only be referenced AFTER here
    RED.nodes.createNode(this, config) 

    // Transfer config items from the Editor panel to the runtime
    this.name = config.name
    this.topic = config.topic

    /** Handle incoming msg's - note that the handler fn inherits `this`
     * The inputMsgHandler function is executed every time this instance
     * of the node receives a msg in a flow.
     */
    this.on('input', inputMsgHandler)

    /** Put things here if you need to do anything when a node instance is removed
     * Or if Node-RED is shutting down.
     * Note the use of an arrow function, ensures that the function keeps the
     * same `this` context and so has access to all of the node instance properties.
     */
    this.on('close', (removed, done) => { 
        console.log('>>>=[4]=>>> [nodeInstance:close] Closing. Removed?: ', removed)
       

        // Give Node-RED a clue when you have finished (more important if your shutdown
        // process includes an async task, make sure done() is executed when the async
        // task completes, not when this function ends).
        done()
    })

    /** Properties of `this`
     * Methods: updateWires(wires), context(), on(event,callback), emit(event,...args), removeListener(name,listener), removeAllListeners(name), close(removed)
     * send(msg), receive(msg), log(msg), warn(msg), error(logMessage,msg), debug(msg), trace(msg), metric(eventname, msg, metricValue), status(status)
     * Other: credentials, id, type, z, wires, x, y
     * + any props added manually from config, typically at least name and topic
     */
    //console.log('>>>=[2b]=>>>', this)
}

//#endregion ----- Module-level support functions ----- //

/** 1) Complete module definition for our Node. This is where things actually start.
 * @param {runtimeRED} RED The Node-RED runtime object
 */
function Test3(RED) {
    // As a module-level named function, it will inherit `mod` and other module-level variables

    // Save a reference to the RED runtime for convenience
    // This allows you to access it from any other function
    // defined above.
    mod.RED = RED

    // Add function calls here for setup that only needs doing
    // once. Node-RED loads this once no matter how many instances
    // of you node you add to flows.
    moduleSetup() // (1a)

    // Register a new instance of the specified node type (2)
    RED.nodes.registerType(mod.nodeName, nodeInstance)
}

// Export the module definition (1), this is consumed by Node-RED on startup.
module.exports = Test3

```

html file:

```html

<script type="text/javascript">
    (function () { // eslint-disable-line strict
        'use strict' // eslint-disable-line strict
    
        RED.nodes.registerType('jktest3', { // eslint-disable-line no-undef
            category: 'Testing',
            color: '#E6E0F8',
            defaults: {
                name: { value: '' },
                topic: { value: '' },
            },
            inputs: 1,
            inputLabels: 'Msg to send to front-end',
            outputs: 1,
            outputLabels: ['Data from front-end'],
            icon: 'ui_template.png',
            paletteLabel: 'jktest3',
            label: function () { return this.name || 'jktest3' },
            
        }) // ---- End of registerType() ---- //
    
    }())
    </script>
    
    <script type="text/html" data-template-name="jktest3">
        <div class="form-row">
            <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
            <input type="text" id="node-input-name">
        </div>
        <div class="form-row">
            <label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
            <input type="text" id="node-input-topic">
        </div>
    </script>

```

---

<div class="post-metadata">

### Author: ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)
#### Post date: [27 October 2021 12:11 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/11 "2021-10-27T12:11:40Z")

</div>

I would strongly suggest sticking to the standard format we use and understand why that is not working in your case before introducing lots of other changes that Julian suggests.

I don't know if anyone here as actually tested the code you've shared to see if this is reproducible - I'll have a proper look when I'm back at my computer later today.

---

<div class="post-metadata">

### Author: ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)
#### Post date: [27 October 2021 12:12 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/12 "2021-10-27T12:12:31Z")

</div>

> [@knolleary](#):
>
> I don't know if anyone here as actually tested the code you've shared to see if this is reproducible - I'll have a proper look when I'm back at my computer later today.

Yes, that's what I just tested. It worked as soon as I fixed the syntax error.

---

<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: [26 December 2021 12:12 UTC](https://discourse.nodered.org/t/node-object-and-closure/52750/13 "2021-12-26T12:12:59Z")

</div>

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