# Initializing config screen based on new config node

**URL:** <https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327>\
**Category:** Developing Nodes\
**Created:** [28 January 2019 09:07 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327 "2019-01-28T09:07:33Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [28 January 2019 09:07 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/1 "2019-01-28T09:07:33Z")

</div>

Hi folks,

In my new [node-red-contrib-onvif-nodes](https://github.com/bartbutenaers/node-red-contrib-onvif-nodes/), I have a config node that contains all the logic to communicate with an Onvif-compliant IP camera. So all my other nodes can get data from the IP camera (via their corresponding config node) to show on their config screen:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/7/7b30854d7a01b34a46a0aca71b7b7a8faeb8d748.png)

1. The Onvif Media node refers to the MyCamKitchen config node, which contains all the logic to connect to the camera in the kitchen.
2. Via the config node, I can get all available **_profiles to show in the dropdown_**. That data is loaded from the config node like this:

```auto
RED.httpAdmin.get('/onvifdevice/:cmd/:config_node_id', RED.auth.needsPermission('onvifdevice.read'), function(req, res){
   var node = RED.nodes.getNode(req.params.config_node_id);
   for(var i = 0; i < node.deviceConfig.cam.profiles.length; i++) {
       // Fill dropdown value list with profiles
       ...
    }
}

```

That works fine as you can see in the above screenshot.  
However this mechanism fails when the user creates a new config node:

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

1. The user creates a new config node, and presses 'Done' on the config node screen.
2. Then Node-RED goes back to the screen of the Media node.
3. At that moment I go to the server (code snippet above) which fails because `RED.nodes.getNode` returns an **undefined**. This is pretty normal since the new config node has not been deployed yet, so I cannot connect to the camera yet...

Has anybody have a better idea to do implement?

Thanks !!!  
Bart

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [28 January 2019 22:52 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/2 "2019-01-28T22:52:00Z")

</div>

I don't think I have many options: The user needs to be able to select an option from a list of profiles.  
But the profile list is not available when the config node is not deployed yet. So in that case the user should be able to enter the profile name manually in a text input field.

As a result I need a text input field with an optional selection list:

- Seems html allows text input to have optional dropdown list(see [datalist](https://www.w3schools.com/tags/att_input_list.asp)). However that is not supported by many browsers...

- So I think **autocomplete** might be a better solution. The user can enter manually a profile name, and (every time the user enters a character) the content of the field will be send to the server-side flow. If similar token names are available, that list of tokens are being displayed in the browser:

Moreover the autocomplete is fairly simple to implement.

1. The node's config screen contains a text input field:

```auto
<div class="form-row actionParam-row" id="profileToken-div">
    <label for="node-input-profileToken"><i class="fa fa-hashtag"></i> Profile token</label>
    <input type="text" id="node-input-profileToken"></select>
</div>

```

2. In the oneditprepare (of the node's config screen), autocomplete functionality is added to that input field (to get profiles as json from the server-side flow):

```auto
oneditprepare: function() { 
    var node = this;
    var cache = {};
         
    $( "#node-input-profileToken" ).autocomplete({
           minLength: 3,
           source: function( request, response ) {
             var term = request.term;
             if ( term in cache ) {
               response( cache[term] );
               return;
             }

             $.getJSON("onvifdevice/profiles/" + node.id + "/" + $("#node-input-profileToken").val(), request, function( data, status, xhr ) {
               cache[term] = data;
               response( data );
             });
           }
         });
}

```

3. And in my config node (on the server-side flow) I return all profiles whose name contains the text that the user has entered:

```auto
RED.httpAdmin.get('/onvifdevice/:cmd/:config_node_id/:search_string', RED.auth.needsPermission('onvifdevice.read'), function(req, res){
     var node = RED.nodes.getNode(req.params.config_node_id);

     if (req.params.cmd === "profiles") {
         if (!node || !node.deviceConfig || !node.deviceConfig.cam) {
             console.log("Cannot determine profile list from node " + req.params.config_node_id);
             return;
         }
        
         var profileNames = [];
         
         for(var i = 0; i < node.deviceConfig.cam.profiles.length; i++) {
             if (node.deviceConfig.cam.profiles[i].name.includes(req.params.search_string)) {
                 profileNames.push(
                     {
                         label: node.deviceConfig.cam.profiles[i].name,
                         value: node.deviceConfig.cam.profiles[i].$.token
                     });
             }
         }
         
         // Return a list of all available profiles for the specified Onvif node
         res.json(profileNames);
     }
 });

```

If I get at least one '_ **like** _', I will implement it this way 😉

**[EDIT]:** you can also download the entire profile list to the browser (in oneditprepare) and do autocomplete based on that client-side cached profile list (see [example](https://jqueryui.com/autocomplete/)). That way there would be less communication to the Node-RED flow ...

---

<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:** [28 January 2019 22:59 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/3 "2019-01-28T22:59:06Z")

</div>

Hi @BartButenaers, I meant to reply earlier, but this is one of those questions that doesn't have a quick response and I haven't had the time to give a proper reply.

The autocomplete route is certainly one way.

The other is to allow the HTTP Admin end point you create to return the information to accept additional query parameters in place of the config node properties.

That way, if the node is 'known' to the runtime, it can use those values to do whatever work is needed to get the data. Otherwise it can use the query parameters to complete the request.

In your node's edit dialog you need to distinguish between a selection of a 'known' config node and a newly added one. There's a trick for that, but I can't quite remember the details - not done it for quite a while.

But there is another scenario to consider - they select an existing (known-to-the-runtime) config node, but then edit the config node to change its details. The node in the runtime no longer matches what they have in the editor, so the list will not be correct. This is all a bit abstract as I don't know what config properties your Device config node has.

So it may be better to change your http admin endpoint to always require the query parameters to be used to specify what data to return - that way it will always be in sync with what the user has entered in the dialog.

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [28 January 2019 23:24 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/4 "2019-01-28T23:24:15Z")

</div>

Also the serial port config node is an example of a select box that you also type into (the port selection field)

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [29 January 2019 21:49 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/5 "2019-01-29T21:49:01Z")

</div>

Hi guys (@dceejay, @knolleary),

> [@dceejay](#):
>
> Also the serial port config node is an example of a select box that you also type into

That is indeed a good alternative to reduce the communication between the browser and the server (compared to my autocomplete solution). Will keep it in mind !

> [@knolleary](#):
>
> this is one of those questions that doesn't have a quick response and I haven't had the time to give a proper reply

Until a few days I thought that Nick knew everything, and that he could answer on all my questions immediately. However after reading this [post](https://github.com/node-red/node-red/issues/256#issuecomment-453734174), it seems that he even doesn't know '_all_' existing frameworks in detail. I am very shock 😂  
Just kidding, I don't expect you to answer all my questions after a couple of seconds ...

> [@knolleary](#):
>
> they select an existing (known-to-the-runtime) config node, but then edit the config node to change its details. The node in the runtime no longer matches what they have in the editor, so the list will not be correct.

That is indeed so true ... That is a big disadvantage of my autocomplete solution. There goes my short moment of glory 🥴

> [@knolleary](#):
>
> The other is to allow the HTTP Admin end point you create to return the information to accept additional query parameters in place of the config node properties.

That would indeed be the best solution. But not sure how to get started with this... Is there perhaps somewhere a node that I could use as an example?

My config node has 3 fields:

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/2/22e974dff26fc7177a87911a0c2f0f81011f5a08.png)

As soon as this config node is deployed, it automatically connects (based on the above 3 settings) to the camera and loads information (e.g. profiles) from the IP camera:

```auto
function OnVifConfigNode(config) {
   var options = {};
   options.hostname = config.ipaddress;
   options.username = config.username;
   options.password = config.password;

   // Create a new camera instance ('onvif' node), which will automatically connect to the device (to load configuration data)
   this.cam = new onvif.Cam(options);
}

```

But it is not clear to me:

- where the 'dirty' config node is stored, when I create a new config node or update an existing config node (until that config node is deployed).
- if I can get hold of that dirty config node data somehow in my code.
- and suppose I could get hold of those dirty config node settings, I would have to create a `'new onvif.Cam(dirtyOptions)'` every time a config screen (of a related node) is shown. That Cam instance will send N requests to the camera to load all kind of information. I assume that will become slow, so autocomplete will be impossible.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [29 January 2019 22:37 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/6 "2019-01-29T22:37:29Z")

</div>

I 'think' will need to do it like this:

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

When I navigate to the config node, and change its name to '_MyCamKitchenUpdated_', and go back to the config screen of my related node: then the change listener of the config node is triggered and I can get hold of the **dirty config node**.

I seems that `RED.nodes.getNode` is called in the flow editor `RED.nodes.node` ...

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [30 January 2019 00:19 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/7 "2019-01-30T00:19:18Z")

</div>

I'm almost there ...  
A **'search' button** (similar to the serial-node) indeed looks nice, at the network traffic is much lower:

![profile_lookup](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/1/1fda60ffc4eb86a6cec5424ed2dc0aec794ada99.gif)

Just need to pass now the information (_username / password / ipaddress_) of the dirty config node (in the browser) to the backend, via the ajax call. But **_the dirty config node doesn't seem to contain the credentials_** :

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/8/83453f8e7aaa2a013b9175fb37c18423f319de92.png)

My (last) questions:

- Is there an easy/secure way to get the credentials in the client-side code?
- Should I pass the data like this to the server?

```auto
$.getJSON("onvifdevice/profiles/" + node.id + "/" + username + "/" + password + "/" + ipaddress, function(profiles) {

```

Or should I pass somehow 3 URL parameters, instead of sub-paths? But perhaps they are not automatically parsed into `req.params` on the server-side?
- Is is safe (even via ssl) to pass those credentials from browser to server, when using the `getJSON` function?

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [30 January 2019 14:39 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/8 "2019-01-30T14:39:02Z")

</div>

I'm having doubt whether it is possible to get the settings of a dirty config node, and send those to my server side flow. Especially since I need to get access to the _ **credentials** _ (username/password) from that config node.

The Node-RED [documentation](https://nodered.org/docs/creating-nodes/credentials#accessing-credentials) tells this:

> Within the runtime, a node can access **its** credentials using the `credentials` property

From a security point of view, it make sense that only a node itself can get access to **its** own properties. And indeed I cannot get access to the username/password:

```auto
RED.nodes.node($("#node-input-deviceConfig").val()).credentials

```

Which returns **undefined**. In fact this is good news, but not for my purpose ...

So I think I should ask to the dirty config node, whether it can connect itself to the camera (based on the dirty credential information to which the dirty config node itself has access). But then again, the dirty config node should be available on the server side flow ... Does anybody know:

- Whether the dirty nodes are available on the server side (before a node is deployed), and if so how I could get an instance of such a dirty node?
- Whether it is possible to send the dirty config node using e.g. `$getJSON` to the server, and deserialize it there somehow?
- Others?

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [31 January 2019 21:37 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/9 "2019-01-31T21:37:32Z")

</div>

Ok have tried all kind of stuff, but I cannot get hold of the _ **dirty credentials** _. So I assume it is impossible to connect to an IP camera (to get its profiles), based on those dirty credentials ...

So up to plan B...  
I want to have at least a warning (that the user should 'Deploy'), which should be displayed as soon as the device config node setting has been changed:

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/2/244348f9621190d83ec9c9f86f0f2ff2e61b1af3.png)

1. I change the settings of the device config node
2. Then I want this text to become visible

This is the code to display/hide that "deployTip" section:

```auto
oneditprepare: function() { 
    $("#node-input-deviceConfig").change(function() {
         $("#deployTip").hide()

         if(this.value) {
             var configNode = RED.nodes.node(this.value);
                    
             if (configNode && configNode.dirty) {
                   $("#deployTip").show();
             }
        }
})

```

However _ **the config node is always dirty** _, even when I haven't changed anything:

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/0/07c807edbfd0179925b58046629e3b2ff234c878.png)

Getting nuts right now 👎👎  
Does anybody have an idea what I'm doing wrong??

---

<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:** [31 January 2019 22:03 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/10 "2019-01-31T22:03:46Z")

</div>

Hi @BartButenaers

For a newly added config node, it will have a credentials object containing whatever has been entered in its edit dialog.

For an existing config node - _that has not yet been edited_ - it will **not** have a credentials object.

When that node gets edited, the editor retrieves credential meta-data for the node from the runtime - which populates `node.credentials`. This meta-data does **not** include the actual value of any credential labelled as a password - just enough meta-data to tell the editor whether a value is known for it.

If the user enters a new value for a password, once the dialog is confirmed, the `credentials` object will have that value until deploy is pressed.

So... you have a couple different cases to handle:

1. if there's no credentials object it means the editor doesn't know the values but the runtime might. Your request to the runtime should include the id of the node and let the runtime do the lookup (as it has full access to credentials).

2. if there is a credentials object it means the user _might_ have provided updated values. Your request to the runtime should in the id of the node and _any of the updated values_. The runtime code can then use the combination of credentials already known to the node with the updated values from the editor.

This feels like one of those replies I'll be bookmarking to referring back to in the future until the proper docs cover this sort of thing.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [31 January 2019 22:07 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/11 "2019-01-31T22:07:44Z")

</div>

Hey @knolleary, very clear explained! Just the kind of info I needed to get started with this.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [31 January 2019 23:48 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/12 "2019-01-31T23:48:23Z")

</div>

Hey Nick (@knolleary),  
The username seems quite easy, but the password content is not clear to me ...

This is the content of the `configNode.credentials` on the client-side (i.e. in the config screen):

- When I neither change the username nor the password, then credentials are **undefined**.

- When I only change the username to 'xxxx', then the credentials contain only the new username:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/a/ac49035de0f4c92029caa21ea5d62ce8e2786e71.png)  
The password is not included, but the boolean shows a password is available (at the server-side).

- When I change the password to 'xxxx', then the credentials contain only the new password:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/0/030d1b94e147dcc989ff0dbbc38bf791708af6bb.png)

- When I change both username and password, then the credentials contain both values.

- When I **append**'xxxx' to the original password, then the credentials contain a constant ` __PWDR___ ` (representing the password which is only known on the server side) combined with my newly added characters:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/d/dab2423444f5f4fea2821d182cfb916232683676.png)  
Could still manage this one: when I send it to the server, I could replace the constant value by the real password value.

- But when I **replace** a few characters of the original password by 'xx', then _a part of the constant value will be replaced_ by my new characters:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/b/b25e4cff335db420db6e3905244a1a0a204feec4.png)  
I have no clue how I could determine which part of the real original password is remained. Indeed if I'm not mistaken, the constant value is always ` __PWDR___ `, undependent of the length of my real original password. Which is of course great from a security perspective, but not for me ...

I see that other nodes (like mqtt) are also dealing with the constant value, but I don't see at first sight how to handle _partial replacements_ of the original password...

Do you have any other tips in your big magic box?

---

<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:** [1 February 2019 00:08 UTC](https://discourse.nodered.org/t/initializing-config-screen-based-on-new-config-node/7327/13 "2019-02-01T00:08:40Z")

</div>

That is because **nothing** handles the partial update of the password. It simple isn't a scenario the code considers - we assume if you are changing the password, then you're setting a whole new one, not blinding editing what's there already.

A better visual representation of the password field is somewhere on my to-do list.

So, my advice, don't worry about those edge cases for now.
