Search code examples
node-red

How to generate the script template elements in a node-red html file


I'm looking for a way to generate, ideally from the <script type="text/javascript"> section, the <script type="text/html"> sections of a node-red node html definition file.

Background context

I'm creating a large number of node-red nodes to access and/or serve an API. The API follows similar patterns for the different resource that it represents, like you'd expect from a REST API. This results in a lot of similar looking nodes like: get-book-action, get-publisher-action, get-author-action, and so on for each of the methods and resources the API exposes.

I've written my node-red node in such a way that I can simply define the list of resources (i.e. const resources = ['book', 'author', 'series', 'publisher', ...]) and have it loop through creating the specific nodes for get, update, etc. The thing I haven't worked out yet is how to do the same for the editor template sections, which is why I'm asking this question.

Pseudo example

I'd like something like this:

<script type="text/javascript">
(function(RED) {
  const resources = ["author", "book", "publisher", ...];
  resources.forEach(resource => {
    RED.nodes.registerType(`get-${resource}-action`, {...});
    RED.nodes.registerType(`update-${resource}-action`, {...});
    RED.nodes.registerType(`delete-${resource}-action`, {...});
    // other verbs

    // some api to create the editor template script tags
    document.write(`
      <script type="text/html" data-template-name="get-${resource}-action">
        <div class="form-row">
          <label for="node-config-input-name><i class="icon-tag"></i> Name</label>
          <input type="text" id="node-config-input-name">
        </div>
      </script>`);
    // and so on for the other verbs/node types and template types like data-help-name
  });
})(RED);
</script>

Solution

  • The script blocks in the .html file of a node-red node simply get inserted into the dom as a child of a div on the editor page. This means that you have the full power of the front-end JavaScript to work with.

    The way I found to accomplish this is with something like the following:

    <script type="text/javascript">
    (function(RED) {
      const resources = ["author", "book", "publisher", ...];
      resources.forEach(resource => {
        RED.nodes.registerType(`get-${resource}-action`, {...});
        RED.nodes.registerType(`update-${resource}-action`, {...});
        RED.nodes.registerType(`delete-${resource}-action`, {...});
        // other verbs
    
        // We have to split up the <scr and ipt parts as if either the opening or closing
        // tags appear anywhere in this block it will close the js script block
        $(document.currentScript).parent().append(
          '<scr'+`ipt type="text/html" data-template-name="get-${resource}-action">
            <div class="form-row">
              <label for="node-config-input-name><i class="icon-tag"></i> Name</label>
              <input type="text" id="node-config-input-name">
            </div>
          </scr`+'ipt>'
        );
        // and so on for data-help-name and other verbs
      });
    })(RED);
    </script>