# Dynamic config dashboard

**URL:** <https://discourse.nodered.org/t/dynamic-config-dashboard/84531>\
**Category:** Dashboard\
**Tags:** node-red-dashboard\
**Created:** [14 January 2024 11:57 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531 "2024-01-14T11:57:06Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![KarolisL](https://avatars.discourse-cdn.com/v4/letter/k/a4c791/32.png) [@KarolisL](https://discourse.nodered.org/u/KarolisL)\
**Post date:** [21 January 2024 17:42 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/21 "2024-01-21T17:42:16Z")

</div>

Thanks for putting everything into tutorial

[![](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/6/9/69b5d1f33ac5e3103a4b68da4b95acf14d4f9a95.jpeg "Code in Node-Red: UIBuilder beginning") ](https://www.youtube.com/watch?v=ngNiKLBwc-Q)

For future users "please subscribe, smash that like button and don't forget to turn on notification to get latest updates" 😄

Seriously man, thanks for vlogging all your stuff

---

<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:** [21 January 2024 18:12 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/22 "2024-01-21T18:12:47Z")

</div>

I'll be reviewing your homework Csongor. 🤣

---

<div class="post-metadata">

**Author:** ![nygma2004](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/nygma2004/32/1308_2.png) [@nygma2004](https://discourse.nodered.org/u/nygma2004)\
**Post date:** [23 January 2024 22:54 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/23 "2024-01-23T22:54:54Z")

</div>

Another live stream done, a form, form submittion, and miscallenaous buttons are working. Very happy with the progress.  
I have a few questions, but could be more HTML/CSS questions that uibuilder. I can ask them here as well, but maybe there should be a generic "uibuilder tips & tricks" topic, or separate topic for each?

- Are there any good examples of a fly-in status message like the toast message in ui-notifications? I assume this would be some floating div with some javasript that moved it out of view after a timeout period.
- Any best practice of handling validation errors with uib-element Simple Form? Error show up above of below the respective form fields?

---

<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:** [24 January 2024 00:21 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/24 "2024-01-24T00:21:11Z")

</div>

> [@nygma2004](#):
>
> a generic "uibuilder tips & tricks" topic, or separate topic for each?

By all means start a "UIBUILDER Tips & Tricks" tag if you like. 🙂

> [@nygma2004](#):
>
> Are there any good examples of a fly-in status message like the toast message in ui-notifications? I assume this would be some floating div with some javasript that moved it out of view after a timeout period.

Never tried that but in general, you'd create the div off-screen and animate it into view.

> [@nygma2004](#):
>
> Any best practice of handling validation errors with uib-element Simple Form? Error show up above of below the respective form fields?

The default brand css gives some simple error highlighting I seem to remember so check out the forms section of the css so you can see how that is done. CSS classes such as `form:invalid xxxx` should allow you to identify inputs that are invalid, maybe `input:invalid`?

You might be able to use things like `input:invalid + div` to select an adjacent element to display/hide. [ref](https://stackoverflow.com/a/15816864/1309986).

> **[:invalid - CSS: Cascading Style Sheets | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid)**
>
> The :invalid CSS pseudo-class represents any , , or other element whose contents fail to validate.

> **[Next-sibling combinator - CSS: Cascading Style Sheets | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Next-sibling_combinator)**
>
> The next-sibling combinator (+) separates two selectors and matches the second element only if it immediately follows the first element, and both are children of the same parent element.

> **[Styling Form Inputs in CSS With :required, :optional, :valid and :invalid |...](https://www.digitalocean.com/community/tutorials/css-styling-form-input-validity)**
>
> No need to rely on JavaScript alone for visual validation cues anymore, thanks to the :required, :optional, :valid and :invalid pseudo-classes.

---

<div class="post-metadata">

**Author:** ![nygma2004](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/nygma2004/32/1308_2.png) [@nygma2004](https://discourse.nodered.org/u/nygma2004)\
**Post date:** [24 January 2024 08:21 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/25 "2024-01-24T08:21:13Z")

</div>

Yes, now I remember the `:invalid` option. But there is no place for the validation message to be included in the simple form JSON right? I mean something like this:

```auto
            {
                "id": "userid",
                "type": "text",
                "required": true,
                "label": "User ID:",
                "value": "info@node-red.org",
                "error": "User id already exists, pick a different userid"
            },

```

I am just saying this, becuase otherwise I would need separate uib-elements probably one for each field to display/hide the validation error divs. Maybe the code can assume that there is a ID `xxx_error` or `xxx_notification` where xxx is the ID of the entry field.

---

<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:** [24 January 2024 19:45 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/26 "2024-01-24T19:45:44Z")

</div>

I will try to add an error blank to forms in the future. You could easily insert something dynamically though if you wanted to.

---

<div class="post-metadata">

**Author:** ![nygma2004](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/nygma2004/32/1308_2.png) [@nygma2004](https://discourse.nodered.org/u/nygma2004)\
**Post date:** [24 January 2024 20:43 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/27 "2024-01-24T20:43:07Z")

</div>

You mean as a separate `uib-element` to populate the "error div"?

---

<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:** [25 January 2024 09:27 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/28 "2024-01-25T09:27:28Z")

</div>

Yes, though you possibly want just a `uib-tag` if inserting a single tag. But you might actually want to insert a placeholder div on all inputs in advance.

At present, there is no zero-code way to update multiple elements with the same addition so you would want to capture the output from a `uib-tag` and amend it to use the `update` method instead of `replace`. With update, you choose the parent as usual but in this case, that would be a CSS Selector that would select - all inputs div wrappers lets say (you'd perhaps need to play with things to get the right selection). Then you should (I've actually not tried this myself I don't think) be able to append a new div marked with a class to hide it. I think this would be best done with some simple front-end JavaScript as it would be more responsive but you could do it from Node-RED as well I think.

I'll try to find some time to run up an example.

---

<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:** [25 January 2024 13:25 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/29 "2024-01-25T13:25:52Z")

</div>

I should also have said that you should remember that you can always grab a copy of the current HTML from the front-end using a simple command from Node-RED:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/4/2/42920d248756affe2191c74794653108e3717b34.png)

You can pass that to a `uib-save` node if you want to have it saved into a file.

This would let you play with the HTML after using no-code to set up the basics.

---

<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:** [25 January 2024 21:28 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/30 "2024-01-25T21:28:24Z")

</div>

> [@TotallyInformation](#):
>
> I'll try to find some time to run up an example.

Maybe better than an example. Here is the content of a function node. Put this immediately after the `uib-element` node that produces your form.

It manipulates the low-code JSON output to add in the extra divs. Adjust to suit.

```auto
// grab the output that contains the child `div`s of the actual form (the rows of the form)
const frmInputs = msg._ui[0].components[0].components[1].components

// Walk through each row
frmInputs.forEach((inp, i) => {
    // Work out the ID for the actual input for this row
    let inpId = frmInputs[i].components[1].id
    // Calculate a matching ID for the error div
    inpId = inpId.replace(/r(\d+)-.*$/, 'r$1-err')
    // Add a new child div to this row
    inp.components.push({
        "type": "div",
        "id": inpId,
        "attributes": {
            // You can use any class you want of course. Starting with all divs hidden
            "class":" hidden inputerror",
        },
        // You might want to use an extra input array to define standard text for each
        // error msg div.
        // slot: stdErrorText[i],

        // You probably also want to not put an error div on the button row.
        // but I'll leave that as an exercise for others. :-)
    })
})

return msg

```

It will work with ANY form output from `uib-element`. All I would say is that, because I'll be needing to update `uib-element` form output in the future, you might need to check that this still works in future releases. I always try to avoid potentially breaking changes but it is possible that this could be one, not totally certain.

Because each form row now has a div to contain error text below the input with a unique ID, you can now easily change the classes or it _might_ be possible to come up with a selector that targets all error divs where its previous sibling has the `:invalid` pseudo-class. ChatGPT probably knows! 😀

If not, you can use the `invalid` event and change classes dynamically.

> **[HTMLInputElement: invalid event - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/invalid_event)**
>
> The invalid event fires when a submittable element has been checked for validity and doesn't satisfy its constraints.

* * *

Let me know how you get on. I will certainly be using the learning from this thread to do future updates to `uib-element`s form output so that you don't need all the messing. I knew forms were a bit simplistic and needed work, this helps focus on what needs doing.

But as you can see, the joy of the no-code output being standard JSON is that it is possible to manipulate it however you want.

---

<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:** [25 January 2024 21:52 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/31 "2024-01-25T21:52:03Z")

</div>

OK, even better.

```js
// grab the output that contains the child `div`s of the actual form (the rows of the form)
const frmInputs = msg._ui[0].components[0].components[1].components

// Walk through each row
frmInputs.forEach((inp, i) => {
    // Add a new child div to this row
    inp.components.push({
        "type": "div",
        // You might want to use an extra input array to define standard text for each
        // error msg div.
        // slot: stdErrorText[i],
        slot: 'ERROR',

        // You probably also want to not put an error div on the button row.
        // but I'll leave that as an exercise for others. :-)
    })
})

return msg

```

So we've got rid of the ID's & attributes because we don't need them at all. Here is some CSS that will show the error divs of EVERY invalid input in the form and hide them otherwise:

```css
form :invalid + div {
    display: block;
    background-color: red;
}
form > div > div {
    display: none;
}

```

---

<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:** [24 February 2024 21:52 UTC](https://discourse.nodered.org/t/dynamic-config-dashboard/84531/32 "2024-02-24T21:52:29Z")

</div>

Closed on 24 February 2024 21:52 UTC

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

[Previous page](https://discourse.nodered.org/t/dynamic-config-dashboard/84531.md?page=1)
