Is it possible to display nested object values directly in ui-builder?

Hi all,

I'm upgrading my dashboard to ui-builder and have been reading the documentation to understand the workflow.

For context, I know that frameworks like Vue can easily display nested variables using syntax like this:

{{ msg.payload.sensors.kitchen.oven }}

My question is about the basic, framework-less ui-builder workflow. My understanding is that to display a simple msg.payload, I can match the msg.topic to an element's id. This works fine for simple data, maybe using something like this:

<span id="more" uib-topic="mytopic">value to be updated</span>

However, I'm struggling when msg.payload is a complex object. I want to display a specific, nested value from it, for example, msg.payload.sensors.kitchen.oven.

It appears I can't use this dot-notation syntax directly in the HTML to extract a nested value from the payload.

Is my understanding correct? Is it impossible to do this directly without custom JavaScript?

Hi Thales, great question.

You can display nested property values, yes. But not quite the way you've tried.

That is because you have used the very simplified uib-topic attribute. When using that, you have to make sure that you map the structure of your msg correctly. Since uib-topic only applies the msg.payload as the innerHTML of the element, you would need to add a node-red change node before sending the msg to remap your nested attribute to the msg.payload.

You do have other options as well though.

The easiest would be to use the uib-var component instead. This is, in fact the exact equivalent of using {{ someDataVar }} in a front-end framework. Except that it has the added advantage that it is a LOT more flexible (in exchange for being slightly more verbose). As you can also pass over attributes as well as HTML in your msg.

In addition, you can also pass more complex data and have it rendered. text , html , markdown , json , table , and list are all supported. The default being html.

<uib-var variable="msg.payload.sensors.kitchen.oven"></uib-var>

Hint: the content is HTML by default, so try a JSON msg.payload of {"sensors":{"kitchen":{"oven":"200 <i style='color:red;'>HOT</i>"}}} :slight_smile:

I will make the documentation for that rather clearer I think.

You could also do it the "old fashioned way" which would be to use some front-end javascript to manage the incoming msg and to update the element directly. This might be more beneficial if you already need to use some front-end JavaScript for other processing. Otherwise, uib-var is the right tool for the job.

As a side-note, if using my web components, they all have a built in feature that lets you send a controlling message direct to the component instance, very similar to using the uib-topic

1 Like

I see. I now understand that uib-var is an HTML tag handled by the ui-builder.js library.
Just to give you a similar example, I have a setup analogous to your SVG. I have been using the Bart node, which, despite being deprecated, is still a great tool, but it requires numerous workarounds.
With ui-builder, I can simply use this approach:

<text x="5" y="15" id="my_sensor">
<uib-var variable="msg.payload.sensors.kitchen.oven"></uib-var>
</text>

With almost 40 sensors whose values are updated by incoming MQTT messages, I am looking for a solution based on {{ msg.payload.rest.of.the.object }}. The goal is to avoid getting too deep into JavaScript to prevent the person I'm helping from getting lost.

The more Nodered manipulations, the better.

However, I still need to manage other properties like style color fill, mouseenter, onclick, and so on. For these needs, JavaScript remains the ideal solution.

Maybe uib-var can solve it as well, but I need more tests and reading.

I think I'll try both methods to leverage the full potential of ui-builder.
That's a very nice hobby of yours. Congratulations!

Which node is that? If there is call for it, I could consider converting it. Hotnipi's gauge, for example, has been converted to a web component and so works natively with uibuilder.

Yes indeed, no JavaScript needed. :slight_smile:

At least some of that is directly controllable from Node-RED using uibuilder. Classes and styles for example. Events are a little harder. UIBUILDER does have the ability to send JS code from Node-RED though typically there is little point, better to simply write it in your index.js file. UIBUILDER also has the uibuilder.eventSend(event) feature which you can attach as the event handler, e.g. onclick="uibuilder.eventSend(event)" which sends a whole bunch of data back to Node-RED automatically. No custom JS needed. But if the data doesn't suite your needs, there is also the uibuilder.send(...) function you can use in your own custom JavaScript. EventSend's advantage is that it deals with the inconsistencies of some of the HTML API's for you. So, for example, you don't have to remember that checkboxes don't set the value property correctly but use checked instead.

And that is at the core of UIBUILDER - the ability to work however you like. combining the best of Node-RED and standard web development workflows. :slight_smile:

Thanks! I enjoy it. :man_mage:

This one node-red-contrib-ui-svg (node) - Node-RED.

It is time to fix some of those workarounds with a new approach ui-builder(ing). Also, despite of loving nodered, I need VSCodium now. My svg is getting bigger, and bigger.
Otherwise it takes too much time.

I will try to keep feeding this topic with informations for other users that want to follow the same path.

I've tested different way uib-var, however, it seems valid only for html. Inside the svg definition it is not processed.

Hmm, well, I can't say that I ever expected anyone to try to embed a web component inside an SVG! That's a new one on me. :rofl:

And the truth is that while SVG's mostly play nice inside HTML, the reverse certainly is not true. Nor is the experience consistent across different browsers I'm afraid. So I don't think your current approach will work.

However, manipulation of an SVG with uibuilder's help is certainly possible as you may have seen from my SVG example flow.

The next low-code approach to try would be to see if the uib-update node works for what you are trying to do. As long as you can target the content with a CSS selector, uib-update should be able to send your data direct to the element. Again though, not sure I've particularly tested that in the exact way you are working.

You should be able to find a suitable CSS Selector with the help of your browser's dev tools.

Feed that into the node's "CSS Selector" field. The Content source should be the msg property to want to output.

Also, because those inputs can come from msg properties, it is possible to have a single uib-update node servicing a large number of different updates.

I'll be honest, I kind of expected this. While the Vue framework works flawlessly, it just doesn't have the same feel.
I'll just stick to a pure JS approach. I'll also incorporate Bootstrap for more advanced styling.

1 Like