Add a custom button to node config UI and onclick() for it

I'm trying to add a button to my custom node's configuration UI.
So in node.html I did this

<script type="text/html" data-template-name="my_node">
    <div class="form-tips"><i class="fa fa-hand-o-down"></i> Press the button to unlock the node backend</div>
    <div class="form-row">
        <label for="node-input-unlock" style="width:20%">
            <button id="node-input-unlock" onclick="unlock(this)">Unlock</button>
        </label>
    </div>
</script>

<script type="text/javascript" src='./config.js'></script>

Then in my JS code

let alert = require('alert');

function unlock(btn) {
	alert("message");
}

I've installed the dependency alert in my node_modules, and restarted the server and client.

But when clicking on the button, nothing happens while I expect to see a pop-up messagebox.

What am I missing?

Without additional build steps you cannot use require in client side JavaScript.

But as alert is a standard built-in function in all browsers, there is no need to require anything.

You should also be checking the browser JavaScript console for errors.

Thanks. Just removed alert and used console.log instead.

It seems that my external script is not found. Errors in browser read:

vendor.js:2 GET http://127.0.0.1:1880/config.js 404 (Not Found)
(index):1 Uncaught ReferenceError: unlock is not defined
    at HTMLButtonElement.onclick ((index):1)

I saved config.js under the same custom node folder along with node.html and node.js of my node.

The inlined-JS in HTML works:

<script>
function unlock(btn) {
	console.log('hello');
}
</script>

Where should I put my supporting scripts file?
I prefer linking HTML to external scripts because I found that VS Code breakpoints don't work with scripts inside the HTML.

Your node's html file should already have a JavaScript section with the call to RED.nodes.registerType(...) in.

So most nodes will place additional javascript they want in there as well:

<script type="text/html" data-template-name="my_node">
    <div class="form-tips"><i class="fa fa-hand-o-down"></i> Press the button to unlock the node backend</div>
    <div class="form-row">
        <label for="node-input-unlock" style="width:20%">
            <button id="node-input-unlock" onclick="unlock(this)">Unlock</button>
        </label>
    </div>
</script>

<script type="text/javascript">
    RED.nodes.registerType('node-type',{
        // node definition
    });

    function unlock(btn) {
        console.log('hello');
    }
</script>

The problem here is you are now defining unlock on the global namespace - that will clash with all of the other javascript loaded in the editor.

There are two things to do to avoid this:

  1. wrap your code in a self-executing function. This prevents it from leaking into the global namespace.
  2. Setup the click handling in your node's oneditprepare function
<script type="text/html" data-template-name="my_node">
    <div class="form-tips"><i class="fa fa-hand-o-down"></i> Press the button to unlock the node backend</div>
    <div class="form-row">
        <label for="node-input-unlock" style="width:20%">
            <!-- removed the onclick handler -->
            <button id="node-input-unlock">Unlock</button>
        </label>
    </div>
</script>

<script type="text/javascript">

(function() {

  RED.nodes.registerType('node-type',{
    // node definition
    oneditprepare: function() {
      $("#node-input-unlock").on("click", function(evt) {
        // the button has been clicked
      });
    }
  });

})();
</script>

As for loading extra javascript files, please read this section of the docs: Loading extra resources in the editor : Node-RED - it explains where to put those files in your module and how to load them in the editor.

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