Uibuilder vue-router without compiling

You can pass props to a router view:

Passing Props to Route Components | Vue Router (vuejs.org)

I want to start by simplest way, set props in index.js and send it to file.vue (in my expample, Page1.vue) but I don't know to pass "props".
I've been following this video-tutorial.
(https://vueschool.io/lessons/route-props?friend=vuerouter)
I've trying doing it for a long time, but I only can do it in this way, but I think is not the correct way, because if props are different for different .vue files, This way can't work.

<!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>http-vue-loader/VueJS Example - Node-RED UI Builder</title>
    <meta name="description" content="Node-RED UI Builder - http-vue-loader/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">
      
        <b-container id="app_container">
            <navbar :routes="myRoutes"></navbar> 

            <h2><router-view :string ="myProps.string" name="routeHeading" :key="$route.fullPath"></router-view></h2>
          
                        
        </b-container>
       
    </div>

    <script src="../uibuilder/vendor/socket.io/socket.io.js"></script>  
    <script src="../uibuilder/vendor/vue/dist/vue.js"></script>     
    <script src="../uibuilder/vendor/http-vue-loader/./src/httpVueLoader.js"></script>   
    <script src="../uibuilder/vendor/vue-router/dist/vue-router.js"></script>
    <script src="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js"></script>
    <script src="./uibuilderfe.min.js"></script> 
    <script src="./index.js"></script>

</body>

</html>

'use strict'




const Page1 = httpVueLoader('./components/Page1.vue');
const Page2= httpVueLoader('./components/Page2.vue')
const navbar=httpVueLoader('navbar.vue')
 

const routeDefs = [
    {
        path: '/',
        name: 'Page1',
        title: 'First Page', 
        components: {
         //   default: IndexView,
            routeHeading: Page1,
        },
        props: {
            string:"From Index",
            number:  33,
            value: "ochenta"
        },       
    },
    {
        path: '/components',
        name: 'Page2',
        title: 'Second Page',
        components: {
         // default:
            routeHeading: Page2,
            
        },
        props: {
            string:"From Index",
            number:  25,
            value: "cincuenta"
        },
        
    }
    ]
    const properties=
    {
        string:"From Index",
        number:  25,
        value: "cincuenta"
    }
// eslint-disable-next-line no-unused-vars
var app1 = new Vue({
    el: '#app',
  
    router: new VueRouter({routes: routeDefs}),
      
    components: {
        
        'navbar':navbar,
        
    }, // --- End of components --- //
   
    data: {
       
     
        myRoutes: routeDefs, // redefine here so we can push it down
        myProps: properties,
      
      

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

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

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

// EOF
<template lang="html">
  <b-container fluid class="pr-5">
    <h2 class="ml-4 mt-4">This is first page</h2>
    <h2>{{string}}</h2
  </b-container>
</template>

<script>

    module.exports = {
    
        
    props: {
        'string': {type: String, default: 'Hello'},
         'number': {type: Number, default: 33},
         'value': {type:String, default: ''}
    },

    /** Any data must be wrapped in a fn to isolate it in case this component is used multiple times */
    data: function() { return {
        

    }}
}
</script>

...And, What about data from .vue file (ie, data picker result) to index.js?

That is for vue-router v4 not v3.

A view is just another component, nothing special about it. So you define the props you want to use:

views/IndexView.vue

<template>
    <div>
        <p>Home, home on the range</p>
        <p>Hello {{myprop}}
    </div>
</template>

<script>
    console.log('>> IndexView >> ', this)

    module.exports = {
        props: {
            'myprop': {type: String, default: 'Nothing Useful'},
        },
    }
</script>

And in your top-level html:

<router-view myprop="genius" :key="$route.fullPath"></router-view>

or more usefully:

<router-view :myprop="someVarName" :key="$route.fullPath"></router-view>

You can also define additional data in the route definition variable that you send to create a new VueRouter.


If you need to pass data from a component to a parallel component, you should investigate the use of Vue state management using stores.

State Management ā€” Vue.js (vuejs.org)

Honestly, you are trying to absorb everything about VueJS via this thread. I strongly recommend doing a short Vue course or at least a few tutorials.

1 Like

Hi @JM_Energy

How are you going with your project?

I scanned through the thread and saw that you hit some road blocks that you have overcome and the last I read was that you are stuck with props. I was new to Vue a year or so ago and found it hard to get props to work, as in, I gave up.

That said, I have an ever growing set of web pages, and they all work perfectly fine without props i.e. in the end I just pass data back and forth via NR from one page to another.

I am not sure if this is what you are trying to do, but in the end it worked really well for me and I haven't looked back.

I'd suggest you just do that.. I can't see any diff in real life performance sending the data via NR.

There is certainly a lot to take in when you move from simply consuming the Vue and bootstrap-vue libraries and using them with uibuilder. However, I've already (been forced to :grinning: ) learn a lot more about vue-router and Vue data flows and it wasn't too hard in the end.

This line in my example index.html shows how to pass data to a view using a prop and how to get data back using a custom event. Neither of which needs a store or vuex and so is very simple to achieve:

<router-view myprop="genius" :key="$route.fullPath" v-on:ooh-you-clicked="myclickmethod($event)">In the slot</router-view>

And an example view component to go with the above:

<template>
    <div :id="$route.name" class="d1"><!-- only 1 root element allowed -->
        <p>Home, home on the range</p>
        <p>Hello {{myprop}}</p>
        <p>Route Name: {{ $route.name }}</p>
        <p title="custom props on the router definiting var are not exposed">Route custom prop 'greeting' (doesn't work): {{ $route.greeting }}</p>

        <p><slot></slot></p>

        <button v-on:click="$emit('ooh-you-clicked', {some: 'thing'})">
            Click Me!
        </button>
        {{ currentRouteData }}
    </div>
</template>

<script>
    console.log('>> IndexView script >> ', this)

    module.exports = {
        props: {
            'myprop': {type: String, default: 'Nothing Useful'},
        },

        computed: {
            currentRouteData() {
                console.log('>>>> IndexView $route >>', this.$route)
                return '' //JSON.stringify(this.$route)
            }
        },

        methods: {
        },

        data: function data() {
            return { // must use return so that each instance of the component has isolation
            }
        },

        created: function() {
            console.log('>> IndexView CREATED >>')
        },
        mounted: function() {
            console.log('>> IndexView MOUNTED >>')
        },
        updated: function() {
            console.log('>> IndexView UPDATED >>')
        },
        destroyed: function() {
            console.log('>> IndexView DESTROYED >>')
        },

        setup() { // Vue v3 only
            console.log('>> setting up IndexView.vue >>')
        },
    }
</script>

<style scoped>
    div#index {
        border: 1px solid rgb(167, 29, 29);
    }
    div.d1 {
        border: 1px solid silver;
    }
</style>

Oh, wow. You did it!

Perhaps I should have asked you that question over a year ago... hehehe!!

Well done @TotallyInformation!

Not sure I'm going to change my build pattern, but a mental note has been set to come here in case I "really" need to do it in the future.

1 Like

Built on the shoulders of giants :grinning: It was Lena who came up with the original guide. I just let it all fester inside my noggin for a year or more and then came back to it to try and answer this and other questions.

1 Like

Hi.

I feel really stupid... :expressionless:

Yes... As we say here: "I wanted to run before learn to walk..." My knowledge in advanced programming is limited. I came from PLC (programmable logic controller) world and I need to learn more about this (for me) new world.
The positive side is that with your help and patient, I was able to do it in my own tests and understand a little more how it works.
I'm still trying to get data from component .vue to node-red.
@alex88 thank you for your tip. That was the first way i thought to do it, but I think @TotallyInformation way has taught us is the best.
@TotallyInformation thanks a lot for help me. You are a very good teacher. Thank you for your patience with me. When I can get data back to node-red in my tests, I got all I need to do a good dashboard for my aplications.

imagen
I get "WoW" when I press button. Thanks again!

1 Like

There are lots of good tutorials for VueJS.

I was recommended the net ninja by @UnborN and it help me a little.

I watched the Vue 2.0 tutorials, as I'm still using 2.0, but you can give this a go if you are using Vue 3.0: Vue JS 3 Tutorial for Beginners #1 - Introduction - YouTube

Also, I agree that what @TotallyInformation information shared is the "best/right" way to do it, but also consider where and how you master your data.

By passing data back to Node-RED, I always know that NR has a complete picture of ALL data.

Whether you use props or pass back and forth, I'd make sure you think about the above, so as to keep your overall design clean and centralised, which will make it easier to come back to and maintain in the future.

The best part, is that once you get over the hump of learning how to do it with uibuilder, it will be very hard to go back to dashboard, except (for me at leas) when I want to visualize something very quickly.

You can access the uibuilder object from any .vue file. Below, I've updated my IndexView.vue view component to include a button that uses the uibuilder.eventSend helper function with the data it sends built from any data-* attributes you add to the button tag. Of course, you can us the normal uibuilder.send function in your methods too. Make sure you show the full msg in Node-RED so that you can see the meta-data that eventSend adds to the message which tells you which tag triggered the event.

<template>
    <div :id="$route.name" class="d1"><!-- only 1 root element allowed -->
        <p>Home, home on the range</p>
        <p>Hello {{myprop}}</p>
        <p>Route Name: {{ $route.name }}</p>
        <p title="custom props on the router definiting var are not exposed">Route custom prop 'greeting' (doesn't work): {{ $route.greeting }}</p>

        <p><slot>This is the slot, this text is replaced if any content is put between the <code>&lt;router-view&gt;&lt;/router-view&gt;</code> tags</slot></p>

        <button v-on:click="$emit('ooh-you-clicked', {some: 'thing'})">
            Click Me!
        </button>
        <button id="sendToNR" @click="doEvent" data-from="from IndexVuew.vue" data-something="else">
            Send to Node-RED
        </button>
        {{ currentRouteData }}
    </div>
</template>

<script>
    console.log('>> IndexView script >> ', this)

    module.exports = {
        props: {
            'myprop': {type: String, default: 'Nothing Useful'},
        },

        computed: {
            currentRouteData() {
                console.log('>>>> IndexView $route >>', this.$route)
                return '' //JSON.stringify(this.$route)
            }
        },

        methods: {
            doEvent: uibuilder.eventSend,
        },

        data: function data() {
            return { // must use return so that each instance of the component has isolation

            }
        },

        created: function() {
            console.log('>> IndexView CREATED >>')
        },
        mounted: function() {
            console.log('>> IndexView MOUNTED >>')
        },
        updated: function() {
            console.log('>> IndexView UPDATED >>')
        },
        destroyed: function() {
            console.log('>> IndexView DESTROYED >>')
        },

        setup() { // Vue v3 only
            console.log('>> setting up IndexView.vue >>')
        },
    }
</script>

<style scoped>
    div#index {
        border: 1px solid rgb(167, 29, 29);
    }
    div.d1 {
        border: 1px solid silver;
    }
</style>

msg:

{
   "uibDomEvent":{
      "sourceId":"sendToNR",
      "event":"click"
   },
   "payload":{
      "from":"from IndexVuew.vue",
      "something":"else"
   },
   "_socketId":"yiD9rF7BbebgCFbqAABt",
   "_msgid":"ccd519b895858d0f"
}

One more time, many thanks!

1 Like

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