UI_Builder - Rendering Data to Table

Trying to figure-out UI Builder, but the following isn't merging the payload. Instead, page is displaying the literal "{{ item.id}}" etc. Same payload will render in the Dashboard Table. Don't assume I know anything

msg.payload = 
<div id="app">
<table id="tbSN">

<tr v-for="item in msg.payload": key="item.id">
    <td>{{ item.id }}</td>
    <td>{{ item.zone }}</td>
    <td>{{ item.layer }}</td>
    <td>{{ item.state }}</td>
    <td>{{ item.addr }}</td>


you are using v-for which is a command for the Vue front end language... but have you create a Vue instance ? please share your complete html and javascript code in order to check and make suggestions.

ps. as an alternative you can read this post that uses bootstrap-vue table

Thanks. I'm trying to follow the bootstrap-vue table example, but still no luck.


<html lang="en">

		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">

		<title>Home Configuration</title>
		<link rel="icon" href="./images/node-blue.ico">

		<link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap/dist/css/bootstrap.min.css" />
		<link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css" />
		<!-- Your own CSS -->		
		<link type="text/css" rel="stylesheet" href="./index.css" media="all">


		<body style="font-size:.9em" class="nr-dashboard-theme">

			<h1>Home Configuration</h1>
			<pre id="msg" class="syntax-highlight">Waiting for a message from Node-RED</pre>
			<div id="app" v-cloak>
			  <b-container id="app_container" class="mt-5">
				<div class="mt-5">
				  <b-table striped hover small :items="items" sort-by="id"></b-table>
		<!-- These MUST be in the right order. Note no leading / -->

		<!-- REQUIRED: Socket.IO is loaded only once for all instances. Without this, you don't get a websocket connection -->
		<script src="../uibuilder/vendor/socket.io/socket.io.js"></script>

		<!-- Vendor Libraries - Load in the right order, use minified, production versions for speed -->
		<script src="../uibuilder/vendor/vue/dist/vue.js"></script> <!-- dev version with component compiler -->
		<!-- <script src="../uibuilder/vendor/vue/dist/vue.min.js"></script>   prod version with component compiler -->
		<!-- <script src="../uibuilder/vendor/vue/dist/vue.runtime.min.js"></script>   prod version without component compiler -->
		<script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js"></script> <!-- Dev version -->
		<!-- <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.min.js"></script>   Prod version -->

		<!-- REQUIRED: Sets up Socket listeners and the msg object -->
		<script src="./uibuilderfe.js"></script> <!-- dev version -->
		<!-- <script src="./uibuilderfe.min.js"></script>     prod version -->

		<!-- OPTIONAL: You probably want this. Put your custom code here -->
		<script src="./index.js"></script>
var app = new Vue({
    // The HTML element to attach to
	el: '#app',
	data() {
		return {
			 items: []  // table data 
	}, // --- End of data --- //

	computed: {}, // --- End of computed --- //

	methods: {}, // --- End of methods --- //

	// Available hooks: beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed, activated,deactivated, errorCaptured

    // Called after the Vue app has been created. A good place to put startup code
    created: function() {
        // **REQUIRED** Start uibuilder comms with Node-RED

    // Called when Vue is fully loaded
	mounted: function() {
		// Keep a convenient reference to the Vue app
		var vueApp = this

        /** Triggered when the node on the Node-RED server
         *  recieves a (non-control) msg
		uibuilder.onChange('msg', function(msg) {
			vueApp.msg = msg.payload; // this is what grabs the msg.payload when injected to UI_Builder

		// Send message back to node-red
		// uibuilder.send({payload:'some message'})
}) // --- End of the Vue app definition --- //
<b-table striped hover small :items="items" sort-by="id"></b-table>

The bootstrap table expects its data to be in in Vue data variable called items
but in your code example you save the received msg.payload in Vue variable msg which is not defined

Change your code to :

uibuilder.onChange('msg', function(msg) {
			vueApp.items= msg.payload; // this is what grabs the msg.payload when injected to UI_Builder
1 Like

Thanks. That works. I still don't understand how ui_builder works, but it works so thats a start.

Have you followed the recent walkthrough? That should really help you understand the basics.

There are really only a couple of things you need to understand about how uibuilder works:

  1. It creates a data link between Node-RED and your front-end web code.

    In your front-end code, you can use uibuilder.send(msg) to send something back to Node-RED and you can use the uibuilder.on('msg', function(msg) {...}) function to listen for messages from Node-RED and apply the message data to your front-end - in the case of using VueJS, you assign it to a VueJS data variable and every time you change that data variable, VueJS updates your UI - but that part isn't uibuilder of course, it is purely VueJS.

  2. It extends Node-RED's web server to make it easy to access some libraries and your custom web code.

    It serves up your custom UI web code and it serves up whatever front-end libraries you want - such as VueJS and bootstrap-vue that are included in some of the examples. But you could install jQuery, RECT or any other front-end framework and use that instead if you prefer, uibuilder doesn't care.

A few other goodies are built in and are being extended for the next release such as the security features and a code editor for your front-end code. But really, those are all nice-to-have's over and above the basics.

First thing I did was your walk-through, which convinced me to give ui_builder a shot. I was bumping up against the limitation of Dashboard, and started looking at http_in > function > template > _http_out which I conceptually understand but got the feeling would end-up requiring a lot of homework to figure-out how to use AngularJS and how to send data back and forth. Then, I came across your walk through.

I have a rudimentary understanding of HTML, CSS and JavaScript. I have no problem throwing together a basic HTML page with a little CSS, but anything beyond basic procedural JS quickly loses me. And, I have no familiarity with these abcdeJS libraries, that I assume are supposed to make things easier than using pure JS but seem like a language in their own right.

What I like about Node Red is a can follow from node to node to node in digestible nuggets. I'm not sure if ui_builder is a black box of magic, or a utility to configure these abcdeJS libraries. I guess its a little of both. After going thru the walk-through and then trying to write HTML on my own, I was quickly stumped by what references to what were required to be in what file (like index.js.)

Then, the particulars of VueJS (as opposed to the few Angular directives I picked-up on messing with the ui_template node). Either Angular is easier, or the Node Red team has integrated it so tightly that the its more seamless. In other words, IDK if I didn't have ui_builder / VueJS configured right or didn't get the basics of VueJS.

I need to go back thru your walk-through and the VueJS tutorials (like the net ninja yt videos) until the light bulb turns on. I still don't know if this is the right direction for me, but I do know Dashboard isn't getting it done.

Well that's about right. They are a bit like a higher-level language and there are some concepts that you certainly need to understand.

Of course, uibuilder doesn't need you to use a front-end framework. If you prefer, you can work with the DOM directly or even the shadow-DOM and HMTL components if you are able to keep to modern browsers.

If you prefer a more traditional, functional approach, you could also use jQuery instead.

It is the former. While there are currently a couple of bits that work directly with VueJS, uibuilder is agnostic to front-end frameworks.

There is actually only 1 file needed and that is index.html. It is called that because of the way that ExpressJS works. ExpressJS is the web server that Node-RED uses. index.html is a common naming convention for web servers and it lets you deliver a web page without having to put something.html in the URL.

It is that file that loads everything else.

The index.js is merely a naming convention to help people keep things straight in their heads. But you can call your .js file anything you like or even squeeze all of your JavaScript into the html file if you really want to. Same for the index.css file.

So look at the html file and you will see everything else that is loaded. You need to load the uibuilderfe.js file of course as that is what provides the client end of the magic.

It is the latter. The Dashboard hides pretty much everything that is going on. VueJS is a MUCH easier framework to work with than Angular. Anglular is OK if you want to write really complex web apps but VueJS starts of easy and scales well. It is, in my view, one of the easiest frameworks to get to grips with that still has the power of any of the major frameworks. There are, however, some up-and-coming frameworks that may well be easier - they just need to mature a little (e.g. Svelte)

index.html is a common naming convention for web servers and it lets you deliver a web page without having to put something.html in the URL.
Ha, at least tham much I already knew!

So, this is all thats needed to create a page in uibuilder

<!doctype html>
		<script src="./uibuilderfe.min.js"></script>	

Circling back to the OP, what is the bare minimum framework I need to dynamically load a table with an Array of Objects in msg.payload?

I eventually need to do more that that, like preload an input form with the data in one table row (Object) by clicking on the row. I aslo need to preload the page with data from another object or array also.

I'm file to render on a monitor only, for the time being. So, I assume I don't need bootstrap.

what is the bare minimum framework I need to dynamically load a table with an Array of Objects in msg.payload?

No framework. You can do it in vanilla javascript.
Perhaps these examples help. (Note the vanilla js/html versions).

in the javascript portion:

uibuilder.onChange('msg', function (msg) {

Once you receive a msg with an array you can populate a table dynamically by either using document.createElement's or writing out html and append it to the body/table. I can make an example if needed.

Nearly :grinning:

 <!doctype html>
		<script src="./uibuilderfe.min.js"></script>

Though in reality, you will want to delay the start until the DOM has loaded so that you don't have to worry about making changes to the DOM before it is ready.

You will also probably want to do something useful with uibuilder as well though. :wink:

Assuming you are using uibuilder v4, the default template shows you the way. It still splits your custom js code to an index.js file but that is only for convenience in development, you don't have to do that, you can merge the code into the html file as I've shown here.

That is absolutely correct. If you can be bothered to code it up using vanilla HTML and JavaScript, you don't need anything else, just build on the basic default template. Of course, what you will end up with is a bare-bones framework so you might question the value.

If you want the easiest way to do what you've asked with minimal learning involved, I would suggest using jQuery as a framework. Especially as there are various excellent table extensions for jQuery.

jQuery has the advantage of being a very familiar programming grammar because it is "functional" and doesn't require you to learn lots of ideas from newer versions of JavaScript.