Uibuilder v2.0.3

Hi i have just updated to Uibuilder V2.0.3 and using the vue template i used to enter my variables here:

const app = new Vue({
    el: '#app',

    data() { return {
    startMsg    : 'Vue has started, waiting for messages',
    feVersion   : '',
    opirstate: "no data", 
    lboffice: "nodata",
    loungepirstate: "no data",
    kitchenpirstate: "no data",
}}, // --- End of data --- //

then address them here
// If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
uibuilder.onChange('msg', function(msg){
console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
app.msgRecvd = msg
app.msgsReceived = uibuilder.get('msgsReceived')
using

if (msg.topic == "officepirontoggle"){app.opirstate =" Breached!"}
       if (msg.topic == "officepirofftoggle"){app.opirstate ="** Safe **"}

then in html putting {{opirstate}}

but this appears to not work not sure what am i doing wrong?
any guidance would be appreciated

Please don't create two separate threads with the same title as this is confusing. Thanks.

Also, is there a reason you are not using uibuilder v4 which is the current version?

Have you run uibuilder.start(this)?

Please post your html and javascript files so that we can see the context.

sorry me bad i will get the current version and see if that solves my problem and run start(this)

i will then post the html and javascript files if no joy

i am using v4 sorry its node-red thats v2 attached html and java

<!

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, initial-scale=1">

    <title>Node-RED UI Builder - VueJS + bootstrap-vue default template</title>
    <meta name="description" content="Node-RED UI Builder - VueJS + bootstrap-vue default template">

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

</head>
<body style="background-color:grey;"> 
  
    <h1>Aldin Way Monitoring</h1>
    <pre id="msg" class="syntax-highlight">Security system</pre>
 
   <div class="row">
<div class="column">
 <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Conservatory door
        <input type="image" img title="Conservatory" src="./common/images/doorclosed.png"  alt = "Door closed" class = "center"  style="width:155px;height:155px;" onclick="return toggleMe('para1','Conservatory door closed','Conservatory door open','./common/images/newdoor.gif','./common/images/doorclosed.png')" value="Toggle" id="para1_img"><br>
<div id="para1" style="display:none">
 </div>
    </div>
    <div class="flip-card-back">
      <h1>Conservatory door.</h1>
      <p>Fibaro door sensor</p>
      <p>Fibaro ID=114</p>
    </div>
  </div>
</div> 
</div>

<div class="column">
 <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Side door
        <input type="image" img title="Side" src="./common/images/doorclosed.png"  alt = "Door closed" class = "center"  style="width:155px;height:155px;" onclick="return toggleMe('para2','Side door closed','Side door open','./common/images/newdoor.gif','./common/images/doorclosed.png')" value="Toggle" id="para2_img"><br>
<div id="para2" style="display:none">
 </div>
    </div>
    <div class="flip-card-back">
      <h1>Side door</h1>
      <p>Fibaro door sensor</p>
      <p>Fibaro ID=131</p>
    </div>
  </div>
</div> 
</div>

 <div class="column">
     <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Front door
       <input type="image" img title="Front" src="./common/images/doorclosed.png"  alt = "Door closed" class = "center" style="width:155px;height:155px;" onclick="return toggleMe('para3','Front door closed','Front door open','./common/images/newdoor.gif','./common/images/doorclosed.png')" value="Toggle" id="para3_img"><br>
<div id="para3" style="display:none">
 </div> 
 </div>
    <div class="flip-card-back">
      <h1>Front door</h1>
      <p>Fibaro door sensor</p>
      <p>Fibaro ID=87</p>
    </div>
  </div>
</div> 
</div>

 <div class="column">
     <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Garage roller door
       <input type="image" img title="Roller door" src="./common/images/roller.png" class="center" alt = "roller door closed" style="width:130px;height:130px;" onclick="return toggleMe('para4','Roller door closed','roller door open','./common/images/roller.png','./common/images/roller.gif')" value="Toggle" id="para7_img"><br>
        <div id="para7" style="display:none">
 </div>
 </div>
    <div class="flip-card-back">
      <h1>Garage roller door</h1>
      <p>universal sensor</p>
      <p>Fibaro ID=175</p>
    </div>
  </div>
</div> 
</div>


 <div class="column">
     <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Office PIR
       <input type="image" img title="Office PIR" src="./common/images/sensoroff.jpg" alt = "Sensor off" class = "center" style="width:131px;height:131px;" onclick="return toggleMe('para4','office pir safe','office pir breached','./common/images/sensoroff.jpg','./common/images/sensoron.jpg')" value="Toggle" id="para4_img"><br>
<div id="para4" style="display:none">
</div>
 </div>
    <div class="flip-card-back">
      <h1>Office PIR</h1>
      <p>{{opirstate}}</p>       <------- this variable not being assigned
      <p>Fibaro ID=8</p>
    </div>
  </div>
</div> 
</div>

<div class="column">
     <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Lounge PIR
      <input type="image" img title="Lounge PIR" src="./common/images/sensoroff.jpg" alt = "Sensor off" class = "center" style="width:131px;height:131px;" onclick="return toggleMe('para5','lounge pir safe','lounge pir breached','./common/images/sensoroff.jpg','./common/images/sensoron.jpg')" value="Toggle" id="para5_img"><br>
<div id="para5" style="display:none">
 </div> 
 </div>
    <div class="flip-card-back">
      <h1>Lounge PIR</h1>
      <p>Fibaro PIR</p>
      <p>Fibaro ID=67</p>
    </div>
  </div>
</div> 
</div>

<div class="column">
     <div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
       Kitchen PIR
      <input type="image" img title="Kitchen PIR" src="./common/images/sensoroff.jpg" alt = "Sensor off" class = "center" style="width:131px;height:131px;" onclick="return toggleMe('para6','kitchen pir safe','kitchen pir breached','./common/images/sensoroff.jpg','./common/images/sensoron.jpg')" value="Toggle" id="para6_img"><br>
<div id="para6" style="display:none">
 </div> 
 </div>
    <div class="flip-card-back">
      <h1>Kitchen PIR</h1>
      <p></p>
      <p>Fibaro ID=62</p>
    </div>
  </div>
</div> 
</div>

    <!-- 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>
</div>
</body></html>

javascript

/* jshint browser: true, esversion: 5, asi: true */
/*globals Vue, uibuilder */
// @ts-nocheck
/*
  Copyright (c) 2021 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://totallyinformation.github.io/node-red-contrib-uibuilder/#/front-end-library */

// eslint-disable-next-line no-unused-vars
const app = new Vue({
    el: '#app',

    data() { return {

        startMsg    : 'Vue has started, waiting for messages',
        feVersion   : '',
        opirstate: "no data", 
        lboffice: "nodata",
        loungepirstate: "no data",
        kitchenpirstate: "no data",
    }}, // --- End of data --- //

    computed: {

        hLastRcvd: function() {
            var msgRecvd = this.msgRecvd
            if (typeof msgRecvd === 'string') return 'Last Message Received = ' + msgRecvd
            else return 'Last Message Received = ' + this.syntaxHighlight(msgRecvd)
        },
        hLastSent: function() {
            var msgSent = this.msgSent
            if (typeof msgSent === 'string') return 'Last Message Sent = ' + msgSent
            else return 'Last Message Sent = ' + this.syntaxHighlight(msgSent)
        },
        hLastCtrlRcvd: function() {
            var msgCtrl = this.msgCtrl
            if (typeof msgCtrl === 'string') return 'Last Control Message Received = ' + msgCtrl
            else return 'Last Control Message Received = ' + this.syntaxHighlight(msgCtrl)
        },
        hLastCtrlSent: function() {
            var msgCtrlSent = this.msgCtrlSent
            if (typeof msgCtrlSent === 'string') return 'Last Control Message Sent = ' + msgCtrlSent
            //else return 'Last Message Sent = ' + this.callMethod('syntaxHighlight', [msgCtrlSent])
            else return 'Last Control Message Sent = ' + this.syntaxHighlight(msgCtrlSent)
        },

    }, // --- End of computed --- //

    methods: {

      
        // REALLY Simple method to return DOM events back to Node-RED. See the 2nd b-button on the default html
        doEvent: uibuilder.eventSend,

        // return formatted HTML version of JSON object
        syntaxHighlight: function(json) {
            json = JSON.stringify(json, undefined, 4)
            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
            json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
                var cls = 'number'
                if (/^"/.test(match)) {
                    if (/:$/.test(match)) {
                        cls = 'key'
                    } else {
                        cls = 'string'
                    }
                } else if (/true|false/.test(match)) {
                    cls = 'boolean'
                } else if (/null/.test(match)) {
                    cls = 'null'
                }
                return '<span class="' + cls + '">' + match + '</span>'
            })
            return json
        }, // --- End of syntaxHighlight --- //

    }, // --- 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() {

        // Example of retrieving data from uibuilder
        this.feVersion = uibuilder.get('version')

        /** **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('/uib', '/uibuilder/vendor/socket.io') // change to use your paths/names
         * @param {Object=|string=} namespace Optional. Object containing ref to vueApp, Object containing settings, or String IO Namespace override. changes self.ioNamespace from the default.
         * @param {string=} ioPath Optional. changes self.ioPath from the default
         * @param {Object=} vueApp Optional. Reference to the VueJS instance. Used for Vue extensions.
         */
        uibuilder.start(this) // Single param passing vue app to allow Vue extensions to be used.

        //console.log(this)

    }, // --- End of created hook --- //

    /** Called once all Vue component instances have been loaded and the virtual DOM built */
    mounted: function(){

        //console.debug('[indexjs:Vue.mounted] app mounted - setting up uibuilder watchers')

        var app = this  // Reference to `this` in case we need it for more complex functions

        // If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
        uibuilder.onChange('msg', function(msg){
            console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
            app.msgRecvd = msg
            app.msgsReceived = uibuilder.get('msgsReceived')
         
           if (msg.topic == "consdooropentoggle"){toggleMeoff("para1","","","./common/images/newdoor.gif","./common/images/newdoor.gif")}
       if (msg.topic == "consdoorclosedtoggle"){toggleMeon("para1","","",'./common/images/doorclosed.png','./common/images/doorclosed.png')} 
           if (msg.topic == "consdooropentoggle"){sendoption("conservatory door open")} 
     if (msg.topic == "consdoorclosedtoggle"){sendoption("conservatory door closed")} 
        
       if (msg.topic == "sidedooropentoggle"){toggleMeoff("para2","","","./common/images/newdoor.gif","./common/images/newdoor.gif")}
         if (msg.topic == "sidedoorclosedtoggle"){toggleMeon("para2","","",'./common/images/doorclosed.png','./common/images/doorclosed.png')} 
         if (msg.topic == "sidedooropentoggle"){sendoption("side door open")} 
         if (msg.topic == "sidedoorclosedtoggle"){sendoption("side door closed")}  
      
       if (msg.topic == "frontdooropentoggle"){toggleMeoff("para3","","","./common/images/newdoor.gif","./common/images/newdoor.gif")}
         if (msg.topic == "frontdoorclosedtoggle"){toggleMeon("para3","","",'./common/images/doorclosed.png','./common/images/doorclosed.png')} 
         if (msg.topic == "frontdooropentoggle"){sendoption("front door open")} 
        if (msg.topic == "frontdoorclosedtoggle"){sendoption("front door closed")} 
         
            if (msg.topic == "rollerdooropentoggle"){toggleMeoff("para7","","","./common/images/roller.gif","./common/images/roller.gif")}
      if (msg.topic == "rollerdoorclosedtoggle"){toggleMeon("para7","","",'./common/images/roller.png','./common/images/roller.png')} 
     if (msg.topic == "rollerdooropentoggle"){sendoption("roller door open")} 
     if (msg.topic == "rollerdoorclosedtoggle"){sendoption("roller door closed")} 
       
        if (msg.topic == "officepirontoggle"){toggleMeoff("para4","","","./common/images/sensoron.jpg","./common/images/sensoron.jpg")}
       if (msg.topic == "officepirofftoggle"){toggleMeon("para4","","",'./common/images/sensoroff.jpg','./common/images/sensoroff.jpg')}
       if (msg.topic == "officepirontoggle"){app.opirstate =" Breached!"}
       if (msg.topic == "officepirofftoggle"){app.officepirstate ="** Safe **"}
       if (msg.topic == "officepirontoggle"){sendoption("office pir breached")} 
        if (msg.topic == "officepirofftoggle"){sendoption("office pir safe")}
        if (msg.topic=="lboffice"){app.lboffice=msg.payload}   
         
            if (msg.topic == "loungepirontoggle"){toggleMeoff("para5","","","./common/images/sensoron.jpg","./common/images/sensoron.jpg")}
          if (msg.topic == "loungepirofftoggle"){toggleMeon("para5","","",'./common/images/sensoroff.jpg','./common/images/sensoroff.jpg')} 
               if (msg.topic == "loungepirontoggle"){app.loungepirstate =" Breached!"}
          if (msg.topic == "loungepirofftoggle"){app.loungepirstate ="** Safe **"}
           if (msg.topic == "loungepirontoggle"){sendoption("lounge pir breached","Security","danger")} 
        if (msg.topic == "loungepirofftoggle"){sendoption("lounge pir safe","Security","success")}
         
           if (msg.topic == "kitchenpirontoggle"){toggleMeoff("para6","","","./common/images/sensoron.jpg","./common/images/sensoron.jpg")}
           if (msg.topic == "kitchenpirofftoggle"){toggleMeon("para6","","",'./common/images/sensoroff.jpg','./common/images/sensoroff.jpg')} 
          if (msg.topic == "kitchenpirontoggle"){app.kitchenpirstate =" Breached!"}
          if (msg.topic == "kitchenpirofftoggle"){app.kitchenpirstate ="** Safe **"}
           if (msg.topic == "kitchenpirontoggle"){sendoption("kitchen pir breached")} 
        if (msg.topic == "kitchenpirofftoggle"){sendoption("kitchen pir safe")}
   
             
        })

        //#region ---- Debug info, can be removed for live use ---- //

        /** You can use the following to help trace how messages flow back and forth.
         * You can then amend this processing to suite your requirements.
         */

        // If we receive a control message from Node-RED, we can get the new data here - we pass it to a Vue variable
        uibuilder.onChange('ctrlMsg', function(msg){
            //console.info('[indexjs:uibuilder.onChange:ctrlMsg] CONTROL msg received from Node-RED server:', msg)
            app.msgCtrl = msg
            app.msgsControl = uibuilder.get('msgsCtrl')
        })

        /** You probably only need these to help you understand the order of processing
         * If a message is sent back to Node-RED, we can grab a copy here if we want to
         */
        uibuilder.onChange('sentMsg', function(msg){
            //console.info('[indexjs:uibuilder.onChange:sentMsg] msg sent to Node-RED server:', msg)
            app.msgSent = msg
            app.msgsSent = uibuilder.get('msgsSent')
        })

        /** If we send a control message to Node-RED, we can get a copy of it here */
        uibuilder.onChange('sentCtrlMsg', function(msg){
            //console.info('[indexjs:uibuilder.onChange:sentCtrlMsg] Control message sent to Node-RED server:', msg)
            app.msgCtrlSent = msg
            app.msgsCtrlSent = uibuilder.get('msgsSentCtrl')
        })

        /** If Socket.IO connects/disconnects, we get true/false here */
        uibuilder.onChange('ioConnected', function(connected){
            //console.info('[indexjs:uibuilder.onChange:ioConnected] Socket.IO Connection Status Changed to:', connected)
            app.socketConnectedState = connected
        })
        /** If Server Time Offset changes */
        uibuilder.onChange('serverTimeOffset', function(serverTimeOffset){
            //console.info('[indexjs:uibuilder.onChange:serverTimeOffset] Offset of time between the browser and the server has changed to:', serverTimeOffset)
            app.serverTimeOffset = serverTimeOffset
        })

        /** If user is logged on/off */
        uibuilder.onChange('isAuthorised', function(isAuthorised){
            //console.info('[indexjs:uibuilder.onChange:isAuthorised] isAuthorised changed. User logged on?:', isAuthorised)
            //console.log('authData: ', uibuilder.get('authData'))
            //console.log('authTokenExpiry: ', uibuilder.get('authTokenExpiry'))
            app.isLoggedOn = isAuthorised
        })

        //#endregion ---- Debug info, can be removed for live use ---- //

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

}) // --- End of app1 --- //
 function sendoption(option){
      
   uibuilder.send({command:option})
   
       }
 function sendtoast(option,title,variant){
      
   uibuilder.send({toast:option,title:title,variant:variant})
   
       }
function toggleMeoff(a,optionoff,optionon,imgsrcoff,imgsrcon){
    
    var e=document.getElementById(a);
    var i=document.getElementById(a+'_img');
       if(!e)return true;
          if(e.style.display=="none"){
           i.src=imgsrcon
        e.style.display="block"
      
sendoption(optionon)
    }
    else{
        i.src=imgsrcoff
        e.style.display="none"
     sendoption(optionoff)
        
    }
    return true;
}
function toggleMeon(a,optionoff,optionon,imgsrcoff,imgsrcon){
    
    var e=document.getElementById(a);
    var i=document.getElementById(a+'_img');
       if(!e)return true;
          if(e.style.display=="none"){
        i.src=imgsrcoff
        e.style.display="block"
 
  sendoption(optionon)
    }
    else{
        i.src=imgsrcon
        e.style.display="none"
       
       sendoption(optionoff)
     }
    return true;
}
function toggleMe(a,optionoff,optionon,imgsrcoff,imgsrcon){
    var e=document.getElementById(a);
    var i=document.getElementById(a+'_img');
       if(!e)return true;
          if(e.style.display=="none"){
        i.src=imgsrcon
        e.style.display="block"


  sendoption(optionon)
    }
    else{
        i.src=imgsrcoff
        e.style.display="none"
        
      
 sendoption(optionoff)
    }
    return true;
}
function showTime(){
    var date = new Date();
    var h = date.getHours(); // 0 - 23
    var m = date.getMinutes(); // 0 - 59
    var s = date.getSeconds(); // 0 - 59
    var session = "AM";
    
    if(h === 0){
        h = 12;
    }
    
    if(h > 12){
        h = h - 12;
        session = "PM";
    }
    
    h = (h < 10) ? "0" + h : h;
    m = (m < 10) ? "0" + m : m;
    s = (s < 10) ? "0" + s : s;
    
    var time = h + ":" + m + ":" + s + " " + session;
    document.getElementById("MyClockDisplay").innerText = time;
    document.getElementById("MyClockDisplay").textContent = time;
    
    setTimeout(showTime, 1000);
    
}

showTime();
 function changecontrol(){
 var image = document.getElementById('controller');
 image.src = "./common/images/controlleron.jpg";
    }
 function changecontrol2(){
 var image = document.getElementById("controller");
 image.src = "./common/images/controlleroff.jpg";
 
    }
    function changestat(){
 var image = document.getElementById('stat');
 image.src = "./common/images/staton.jpg";
    }
 function changestat2(){
 var image = document.getElementById("stat");
 image.src = "./common/images/statoff.jpg";
     }
 function switchcontrol(){
 var image = document.getElementById('para22_img');
if(msg.payload=="00:00:25"){alert("now")
}
    };
  <p>{{opirstate}}</p>       <------- this variable not being assigned in html

hope this helps?

It took a bit of searching, but I think I spotted the error. If you look at the start of the Vue code in your javascript file, it shows the following:

const app = new Vue({
    el: '#app',
// and so on

What this means is that it searches for an element with id app in your HTML, and uses that as entry point to connect the Vue application on. That is the start of the code/templates in your HTML that will be replaced.

Looking at your HTML code, I'm missing an element like a

surrounding everything else with an ID set to "app". Meaning the Vue app doesn't connect to your web page, and thus nothing is being replaced.

For more info, see this section of the Vue docs: Introduction — Vue.js
The DOM element it is referencing in your Javascript code, is missing from the HTML, so the code has no actual entry point to start operating from.

Good spot as always :slight_smile:

Yes @magicman, you've removed something that was in the template and critical for VueJS to work. In keeping with most frameworks, Vue needs a starting element. I believe that you can, if you want to, attach that to the body element but best practice is to create an outer DIV.

The other thing it looks like you've done that you really don't want to is to have the SCRIPT links inside a div. They should be inside the body but outside any div's because they don't belong in the visible DOM.

1 Like

ty @TotallyInformation but i am not sure what i have done i just loaded the vue template . i am extremley new to this programming so cant always follow you experts . so consequently not sure what i have to do?

thank you @TotallyInformation and @afelix you pointed me in the right direction. i began again and used the simple vuejs template and moved the scripts outside the div all works well now , thanks for the time you give us newbies!

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