UI Builder change background color depending on the displayed value

Hello, how can I dynamically change the background color of the current value?

The value gValue.toFixed (0) is displayed.
But I want the background to turn red as soon as the value goes into the minus range.

Can someone please help me!

Hi Chris,

Are you using Vue in your project ?
If yes then you should use something called vue class binding ..
to add and remove a class (on the div that holds gValue) that you can then style with the appropriate css.

Also you havent shared the index.js file so there not much information to suggest any solutions.

Vue - Dynamic CSS Classes

Hi Andy,

I'm only at the very beginning with Uibuilder, I've taken an existing program and try to design it according to my ideas.
Here is my index.js
Thank you for your help


/* jshint browser: true, esversion: 5 */
/* globals document,Vue,window,uibuilder */
// @ts-nocheck
/*
  Copyright (c) 2019 Julian Knight (Totally Information)

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/
'use strict'

/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */

// eslint-disable-next-line no-unused-vars
var app1 = new Vue({
    el: '#app',
    data: {
        gValue: 3,
        gValue1: 3,
        gValue2: 3,
        gValue3: 3,
      
    }, // --- End of data --- //
    computed: {
    }, // --- End of computed --- //
    methods: {
    }, // --- End of methods --- //
    
    

    // Available hooks: init,mounted,updated,destroyed
    mounted: function(){
      
        uibuilder.start()

        var vueApp = this

        // Process new messages from Node-RED
        uibuilder.onChange('msg', function (newVal) {
            // We are assuming that msg.payload is an number between zero and 10

            // Change value
            vueApp.gValue = newVal.payload[0]
            vueApp.gValue1 = newVal.payload[1]
            vueApp.gValue2 = newVal.payload[2]
            vueApp.gValue3 = newVal.payload[3]
            //console.log(vueApp.gValue)
        })

    } // --- End of mounted hook --- //

}) // --- End of app1 --- //

// EOF

here my code from index.html

<!doctype html><html lang="en"> <head>
    

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">

    <title>vue-svg-gauge/VueJS Example - Node-RED UI Builder</title>
    <meta name="description" content="Node-RED UI Builder - vue-svg-gauge/VueJS Example">

    <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" />

    <link rel="stylesheet" href="./index.css" media="all">
    
   
</head>
<body>
    
    
    
 <div id="app">  
 <font color= cyan>{{gValue.toFixed(0)}}</font>
  
  <a class="link short" style="margin: 100px auto auto 100px;"><div id='p2' div class="nio">{{gValue.toFixed(0)}}</div></a>
  <script>
  var back = -1;
  var bodybg;
  if (back >=0){
      bodybg = 'green';
  }
  else{
       bodybg = 'red';
  }
 document.getElementById("p2").style.backgroundColor = bodybg;
</script>

    </div>  
 
  <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
    <script src="../uibuilder/vendor/vue/dist/vue.min.js"></script>
    <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js"></script>

    <!-- Loading from CDN, use uibuilder to install packages and change to vendor links -->
    <script src="https://unpkg.com/vue-svg-gauge@1.2.0/dist/vue-svg-gauge.min.js"></script>

    <script src="./uibuilderfe.min.js"></script> <!--    //prod version -->
    <script src="./index.js"></script>  
 
   

</body></html>

Ah, OK. You need to take a slight step back from the problem and give some thought to how VueJS works and how it is supposed to help you write a nice UI easily. :smiley:

  1. The point of a separate index.js and index.html is to let you focus on the UI design in the html and the code or processing in the .js file. So it is best to avoid extra script tags in your html.

  2. a front-end framework like VueJS (or indeed REACT, Angular, etc) is designed to take care of the update of the DOM (the structure of your web page). So you should avoid doing document manipulations by hand.

  3. Avoid the use of the <font> element, that is very old-school and mixes formatting with the layout which gets very hard to maintain. Instead, build your font information into CSS Classes. Or even just use a style attribute if you really must.

So, in the case of VueJS, all you need to know is that while you can include JavaScript within moustaches {{ ... }} wherever you would otherwise put text in your HTML, you need to use different syntax for making attributes dynamic.

<div id="p2" v-bind:style="back>=0 ? 'background-color:green' : 'background-color:red' ">

Better still, make youe back data variable into the style text then all you need is:

<div id="p2" v-bind:style="back">

or even (note that here you have a javascript object expressed as text) so that back only needs to contain the colour name or indeed could be any CSS colour specification such as hsl(149,255,92) (which is official NHS Blue in case you were interested).

<div id="p2" v-bind:style=" {'background-color': back} ">

This can, if you like, be shortened to:

<div id="p2" :style="back">

Have a read of the page here:

This is only the start of what you can do. For example, you could change that data variable back into a dynamic computed function. That lets you build the logic into something that automatically gets recalculated when some other value changes. Both computed functions and data variables, when updated, automatically rebuild the parts of the DOM that they impact and nothing else. It is very efficient and very easy to work with.

Nice .. one small note .. Looking at the Chris' Vue data, the variable being dynamically updated from uibuilder is gValue .. better to use that in the style binding and delete that extra script tag in the index.html

<div id='p2' div class="nio" v-bind:style="gValue>=0 ? 'background-color:green' : 'background-color:red'">{{gValue.toFixed(0)}}</div>

I wasn't trying to give a full answer, only show the way :smiley:

yeap .. it seems that Chris has some studying to do :wink:

@ChrisWeb71 may i recommend a very good video playlist that covers Vue basics

Vue JS Tutorial

1 Like

hello, thanks for the quick feedback.
You guys helped me a lot.
Vue is still completely new territory for me.
Thanks again

It is a fun journey. :smiley:

Definitely, do have a play with the basics and maybe follow that tutorial - all using uibuilder so you get familiar with the interactions. The uibuilder part is actually really simple. At the moment the front-end uibuilderfe library mainly ensures that you have a robust websocket comms channel to/from Node-RED along with a simple event handler to detect incoming msgs - and a function to send msgs of course.

More is on the way for v3 of uibuilder:

  • The start of better built-in security features that will let you have bespoke authentication and authorisation while uibuilder takes care of the heavy lifting for you.
  • The start of some VueJS helpers that will simplify the front-end HTML and JavaScript development by taking care of sending data and configuration direct to Vue components from an incoming msg from Node-RED. (Still without lock-in to Vue though so you can still use uibuilder with any - or no - front-end library.

Hello, me again.
Changing the background color depending on the value of the variable works great.

Now I have the next problem I realized the whole thing with a circle.
That works as it should.
But I do not want to succeed that the circle flashes with red and not with green.

Can you give me another tip?

this is my code

<a class="circle" style="margin: 10px auto auto 10px;"><div class="io" v-bind:style="gValue>=0 ? 'background-color:green' : 'background-color:red'"></div></a> 

greetings chris

Sorry, I think there is a translation problem there, I can't quite work out what you want to do.

Hi,
I want the background to flash red when the value is less than zero.

so e.g. like in this example

if my gValue> = 0 you should see the pulsating circle and if gValue <0 the pulsating circle should be invisible

Hi Julian,
I'm currently in the process of integrating Node Red into my company.
i want to visualize the production numbers.
I want to create an appealing website to convince my boss.
My question, how many simultaneous connections can the website created with UIBuilder, are there restrictions, such as IIS on a Windows 10 workstation?

Hi,

I solved the problem with the blinking circle

I created 2 classes, one green point and the other red flashing point

<a class="circle" style="margin: 10px auto auto 100px;"><div v-bind:class="gValue>=0 ? 'io' : ' nio'"></div></a>  

There are too many ways to do that! The simplest would be to swap a static image with an animated gif for example. You can change images using just CSS.

That isn't a uibuilder question. The uibuilder answer is that there are no restrictions. But that doesn't help you.

The restrictions come from Node-RED and the device (server) that it runs on.

If you run on a Windows 10 desktop/laptop, you will certainly be restricted because Microsoft place an artificial limit on the number of inbound connections.

To get the best performance from uibuilder, you will need to investigate using a reverse proxy such as HAproxy or NGINX or Caddy. Get the proxy to offload as much of the work from Node-RED as possible since it will be a lot more efficient at handling web resources than the ExpressJS server built into Node-RED. It is impossible to realistically predict how many users will be supported in a particular environment and that is a question for an operational specialist anyway. Build it and try it. Test it.

Hello everybody,
I have another problem with a line chart and I want to feed the example Multi series line chart with data from the newVal.payload.
But I can't do it.
what am I doing wrong?
I have no idea how to get the array behind the identifier
({name: 'Workout', data: {'2017-01-01 00:00:00 -0800': 3, '2017-01-02 00:00:00 -0800': 4}},)

greetings Chris

'use strict'
var app1 = new Vue({
    el: '#app',
    data: {
        // Multi-series line chart
 
 //  lineChartData2: [
 //           {name: 'Workout', data: {'2017-01-01 00:00:00 -0800': 3, '2017-01-02 00:00:00 -0800': 4}},
 //           {name: 'Call parents', data: {'2017-01-01 00:00:00 -0800': 5, '2017-01-02 00:00:00 -0800': 3}},
  //      ],

 
 
     lineChartData2:[],

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

    // Available hooks: init,mounted,updated,destroyed
    mounted: function(){
        /** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3
         * Pass the namespace and ioPath variables if hosting page is not in the instance root folder
         * e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.
         * e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names
         */
        uibuilder.start()
 var vueApp = this
        // Process new messages from Node-RED
        uibuilder.onChange('msg', function (newVal) {
            // We are assuming that msg.payload is an array like [datenum, value]

            // Add new element
         //   vueAp
       //  vueApp.areaChartData.push(new Array( (new Date(newVal.payload[0])), newVal.payload[1]));
    
        vueApp.lineChartData2.push({name: 'Call parents', data: {new Array( (new Date(newVal.payload[0])),newVal.payload[1])}})
   
            
            if ( vueApp.areaChartData.length > 1000 ) vueApp.areaChartData.shift();

            //console.log(vueApp.areaChartData)
        })

    } // --- End of mounted hook --- //

}) // --- End of app1 --- //
// EOF

Hi Chris,

What is the structure of the msg you send from Node-red to uibuilder ?
You can check by adding a console.log(newVal) right after the uibuilder.onChange(...) line.

I haven't tried this chart example but from that comment line it assumes the msg.payload to
be an array [datenum, value].
is the message you're sending like this ? for example. payload: [1602790665691, 33]

Hello Andy,

yes, that's exactly how my payload looks like: payload: [1602790665692, 21] if I create a single line chart it works.
but when I create a multi line chart it shows nothing.
how do I get the chart to look like this:
{name: 'Workout', data: {'2017-01-01 00:00:00 -0800': 3, '2017-01-02 00:00:00 -0800': 4}},

thanks and greetings Chris