I'm creating my first node in a while and I am using Object.assign() to set default values on a config object. For some reason this throws an error:
18 Dec 08:05:37 - [error] TypeError: Cannot read property 'handleError' of undefined
at VirtualDimmerConstructor.Node.error (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:524:30)
at /usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:210:26
at Object.trigger (/usr/lib/node_modules/node-red/node_modules/@node-red/util/lib/hooks.js:149:13)
at VirtualDimmerConstructor.Node._emitInput (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:196:11)
at VirtualDimmerConstructor.Node.emit (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:180:25)
at VirtualDimmerConstructor.Node.receive (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:479:10)
at Immediate.<anonymous> (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/flows/Flow.js:814:52)
at processImmediate (internal/timers.js:464:21)
Object.assign() has been available since node 4 so I can't see why this would blow up...
I imagine that some people might come back and say "that's not how you're supposed to deal with defaults". This question is not about what the code is doing (currently this is very bare bones and just to make sure I can get a node working in node-red) but about why Object.Assign doesn't work. It's a feature that I use quite a bit in my coding so doing without it would be a pain!
18 Dec 11:43:15 - [error] TypeError: Cannot read property 'handleError' of undefined
at VirtualDimmerConstructor.Node.error (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:524:30)
at /usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:210:26
at Object.trigger (/usr/lib/node_modules/node-red/node_modules/@node-red/util/lib/hooks.js:149:13)
at VirtualDimmerConstructor.Node._emitInput (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:196:11)
at VirtualDimmerConstructor.Node.emit (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:180:25)
at VirtualDimmerConstructor.Node.receive (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:479:10)
at Immediate.<anonymous> (/usr/lib/node_modules/node-red/node_modules/@node-red/runtime/lib/flows/Flow.js:814:52)
at processImmediate (internal/timers.js:464:21)
I'm confused by @Steve-Mcl message. Object.assign can merge multiple objects... I must be missing something...
My intention here was to set default values for the node config. What I didn't realise was that I was effectively throwing away the entire node object and creating a new one that I was trying to assign property values to. Node red was unhappy about that (presubably as we were trying to give it a node object that it hadn't created and knew nothing about) and threw some error.
I presume that there is probably a map of node instances somewhere so my new object was not in it and stuff blew up.
Now that I know what was going on I'll delete that code and write it a different way!!!
Thanks for the responses.
You don't have to start with an empty object {}, you can start with an existing object if you prefer. But you can have as many other arguments to the function as you like and they will all be merged into the first listed object. However, Object.assign only checks the top-level of objects and does not do any merging below that level - it just overwrites. The MDN entry has the details.
With the config object, what normally happens in your node's .js file is that you apply each config entry to the node's this object manually. So the easiest way to do what you want is to check whether the config entries with defaults have a real value in config and if not, apply the default value. There are lots of examples in existing nodes including my own uibuilder nodes. It is a very common requirement.
nope. It was the fact that was returning an incorrect node object to node red.
All arrow functions do is mainting the current this value. If this is undefined or bannana that same value will be used. An incorrect this value won't kill the function.
an arrow function is the same as: myFunction.apply(this, someParam)
There was a similar issue a while ago where the fix was to not use arrow functions. I assumed you were hitting the same thing.
A previous version of the Node code set a custom this context for the event handlers to deal with scoping function calls to individual messages. But looking through the code (bits of which I haven't touched for a year or more) I can see I was wrong and it doesn't do that anymore.
What was wrong with it and how did you fix it? Given I can't see anything immediately wrong with the code you shared at the start, it would be helpful to know what you changed so we can spot it in the future.
In the first case we are retaining the same object instance for the node rather than returning a new node with a shallow copy of the old node's properties.
yes, you're right. I was trying to demonstrate what fixed the exception and in the process got the defaulting wrong.
So. Something like this:
const config = Object.assign(defaultConfig, partialNode); // all config properties have a value
const node = Object.assign(partialNode, config); // assign all config properties to node