UI-Builder and Vuetify not working

I can't seem to get node-red-uibuilder [most up to date version 5.1.1] and vuetify to work. After installing the package I followed the information in this post. Also reading through the documentation in vuetify I can't seem to get a component to load.

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

    <title>EI</title>
    <meta name="description" content="EIC">
    <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 href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.x/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="../uibuilder/vendor/vuetify/dist/vuetify.min.css" rel="stylesheet">
    <link rel="icon" href="./images/node-blue.ico">

    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

</head><body>
    <div id="app">
        <myheader></myheader>
        <b-container fluid>
            <router-view></router-view>
       </b-container>
     </div>
    </head>
    <body>
    
    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
    <script src="../uibuilder/vendor/vue/dist/vue.js"></script>
    <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js"></script>
    <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue-icons.js"></script>
    <script src="../uibuilder/vendor/http-vue-loader/src/httpVueLoader.js"></script>
    <script src="../uibuilder/vendor/vuex/dist/vuex.js"></script>
    <script src="../uibuilder/vendor/vuetify/dist/vuetify.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>
    <script src="./uibuilderfe.min.js"></script>
    <script src="../uibuilder/vendor/vue-router/dist/vue-router.js"></script>
    <script src="./uibuilderfe.min.js"></script>
    <script src="./index.js" type="module"></script>

</body></html>

index.js

'use strict'

import router from './router.js';

// eslint-disable-next-line no-unused-vars
new Vue({
    el: '#app',
    vuetify: new Vuetify(),
    components: {
        'mycomponent': httpVueLoader('./components/mycomponent.vue'),
        'myheader':httpVueLoader('./components/myheader.vue'),
    },
    data(){
        return { };
    }, 
    computed:{
    },
    methods: {
    }, 
    mounted: function(){
        
      //navigates to home page at mount
      this.$router.push('/home'); 

        uibuilder.start()
        var vueApp = this
        uibuilder.onChange('msg', function(newVal) {
        });
    },
    router: new VueRouter(router),
})

Any help is appreciated. Thank you

Have you ensured that you have installed VueJS v2 and not v3 which is the current default? Like bootstrap-vue, the Vuetify project has not yet upgraded to work with VueJS v3.

I'm am currently using vue 2.7.14 so I'm not on vue3 which I did read it doesn't work with v3

This looks a bit weird but shows that Vuetify is working:

index.html

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

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

    <title>VueJS + Vuetify - Node-RED uibuilder</title>
    <meta name="description" content="Node-RED uibuilder - VueJS + Vuetify">

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

    <link href="../uibuilder/vendor/vuetify/dist/vuetify.min.css" rel="stylesheet">
    <link type="text/css" rel="stylesheet" href="./index.css" media="all">

</head><body>

    <div id="app" class="uib" v-cloak>
        <v-app>
            <v-app-bar app></v-app-bar>

            <h1>uibuilder + Vue.js + Vuetify for Node-RED</h1>
            
            <pre id="msg" v-html="showLastReceivedMsg" class="syntax-highlight">Waiting for a message from Node-RED</pre>

            <v-main>
                Hello World
            </v-main>
        </v-app>

    </div>

    <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->
    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>
    <script src="../uibuilder/vendor/vue/dist/vue.js"></script>
    <script src="../uibuilder/vendor/vuetify/dist/vuetify.js"></script>
    <script src="./uibuilderfe.min.js"></script>
    <script src="./index.js"></script>
    <!-- #endregion -->

</body></html>

index.js

/* jshint browser: true, esversion: 5, asi: true */
/*globals Vue, uibuilder */
// @ts-nocheck
'use strict'

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

        lastMsg    : '[Nothing]',

    }}, // --- End of data --- //

    computed: {

        // Show the last msg from Node-RED nicely formatted
        showLastReceivedMsg: function() {
            var lastMsg = this.lastMsg
            if (typeof lastMsg === 'string') return 'Last Message Received = ' + lastMsg
            return 'Last Message Received = ' + this.syntaxHighlight(lastMsg)
        },

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

    methods: {

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

    /** Called after the Vue app has been created. A good place to put startup code */
    created: function() {

        uibuilder.start(this) // Single param passing vue app to allow Vue extensions to be used.

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

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

        const 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
        uibuilder.onChange('msg', function(msg){
            app.lastMsg = msg
        })

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

}) // --- End of app definition --- //

// EOF

This looks a bit better:

    <div id="app" v-cloak>
        <v-app>
            <v-app-bar app></v-app-bar>
            <v-main>
                <v-container>
                    <h1>uibuilder + Vue.js + Vuetify for Node-RED</h1>
                    
                    <pre id="msg" v-html="showLastReceivedMsg" class="syntax-highlight">Waiting for a message from Node-RED</pre>                    Hello World
                </v-container>
            </v-main>
        </v-app>
    </div>

Sweet thanks for the help. It looks like the index.html what fixed the issue where the components weren't loading.
Also appreciate the edits to the index.js

Any idea how to use vue-router with this like I had in the previous index.js? I tried adding it but I'm just getting an import error.

Figured it out for anyone wondering adding type="module" fixed my issue

<script src="./index.js" type="module"></script>
<script src="./router.js" type="module"></script>
1 Like

Just an FYI that Vuetify 3.0.2 has been released, using Vue 3, and it works well, except that some complex components are not yet available. I'm using it for FlexDash and unless you need those complex components in the next couple of months I would not recommend to start anything new using Vuetify 2.x at this stage. Porting to 3.x is not a tremendous amount of work but not painless: you won't need to change the structure of your app but lots of little details.

1 Like

Thanks for letting us know. I still think that the Vue project handled the transition from v2 to v3 very badly. It will be interesting to see how long it takes bootstrap-vue to migrate.

One of the issues with Vue v3 is that there are now multiple ways of doing some things and different tutorials do them in different ways which is extremely confusing for beginners. Indeed, in my view, the "new" ways of working with Vue are far more confusing and this is an unfortunate trend I see in most frameworks. That progression leads to a significant jump in complexity. This may be OK for people who are professional developers and work with the framework daily but it is a pretty horrible experience for those who don't. I originally chose Vue as the main examples for uibuilder because it was relatively easy to do simple things and relatively easy to understand how to do simple things. Vue v3 undermines that. This was one of the reasons that, in uibuilder v5, I decided to remove the couple of Vue-specific adaptions and made sure I went back to one of the founding principles of uibuilder which was to be framework agnostic.

Anyway, rant off. I agree that if you can get your head around Vue v3 and as long as any components you may wish to use are v3 compatible, it is the better choice at this point.

I really do need to get the build helpers in place un uibuilder to make it easier to use frameworks such as Svelte which, at least right now, doesn't suffer from these complexity issues and is far more "svelte" all round. :sigh:, never enough time.

Thanks again, JK.

I agree that the new composition API is more confusing and complex, however, that's not a reason not to continue using the "old" options API, which is unchanged. I.e., as far as I know there is no Vue2/Vue3 compatibility issue and the options API remains a very nice and easy to learn way of writing components. The Vue team is also pretty clear about supporting both APIs going forward, it's not like the options API is deprecated.

In FlexDash I'm continuing to use the options API 'cause I'm hoping that this will make it easier for others to write their own widgets and such. I may convert some internal stuff to the composition API to make reuse easier, but I'm not rushing. The reason Vuetify took so long to port to Vue3 is that they decided to fully rewrite using the composition API, can't really blame Vue for that... (But Vuetify did get a big benefit from it in the end.)

I think the real problem is React :rofl:. Vue2 was being derided as being less powerful than React, so they had to do something. For me, I don't care what React does or offers, it's even worse to use than Vue3's composition API. :roll_eyes:

1 Like

Yup! And Angular is an order of magnitude worse still!

It is a shame that native W3C components are so badly implemented, they really should be the answer but they are pretty bad too sadly.

Anyway, we are far off topic now. In the end, I agree that Vue3 is sensible to use if the components and frameworks you want support it. Otherwise, you'll end up re-writing anyway in a year or two.

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