I agree! Being able to start Vue with Node-Red data plasticity helped by uibuilder is really great, but it's a pain to understand at first, too many details and a hard time to tackle problems. Steep learning curve!
Hopefully a great community goes a long way 
Actually I want to call different videos so I guess the container is the best way in my case.
Removing the first player and moving options to inde.js
    data: {
        player: null,
        videoOptions: {
			class:"video-js",
            controls:true,
            preload:"auto",
            width:640,
            height:264,
			sources: [
throws new errors:
[Vue warn]: Error in mounted hook: "TypeError: The element or ID supplied is not valid. (videojs)"
(found in <Root>) vue.js:634:17
    VueJS 11
    <anonymous> http://192.168.1.236:1880/videojs/index.js:3
TypeError: The element or ID supplied is not valid. (videojs)
Nope, I don't think so, you are over-complecating things. A single player will show as many videos as you like (1 at a time), simply send a new one from Node-RED. Or, better still, send a list of videos with metadata from Node-RED to your front-end, use that list to build a dropdown and use the change event on the dropdown to load the appropriate video and start playing.
Then I still miss something in the setup 
How would I do that?
What about the error?
The error gives a clear indication where to look.
You mentioned that you removed the first video player component from Julian's example.
But in index.js in mounted() the code tries to initialize a player in an element with id 'my-video' and none is found.
 app.player = videojs('my-video')
        console.log(app.player)
I didnt study the code in depth but try use an id="my-video" on the second player that you have in your modified code.
Thanks @UnborN
In index.html, I'd like to keep <video-player :options="videoOptions"/> to understand the uibuilder-Vue mechanic.
So here's my index.js:
'use strict'
new Vue({
    el: '#app',
    
    components: {
        'video-player': httpVueLoader('video-player.vue'),
    }, // --- End of components --- //
    
    data: {
        player: null,
        videoOptions: {
			id:"video-player",
			class:"video-js",
            controls:true,
            preload:"auto",
            width:640,
            height:264,
			sources: [
				{
					src:
						'//vjs.zencdn.net/v/oceans.mp4',
					  type: 'video/mp4'
				}
			]
		},
		videoUrl: '',
		
        startMsg    : 'Vue has started, waiting for messages',
        feVersion   : '',
        counterBtn  : 0,
        inputText   : null,
        inputChkBox : false,
        socketConnectedState : false,
        serverTimeOffset     : '[unknown]',
        imgProps             : { width: 75, height: 75 },
        msgRecvd    : '[Nothing]',
        msgsReceived: 0,
        msgCtrl     : '[Nothing]',
        msgsControl : 0,
        msgSent     : '[Nothing]',
        msgsSent    : 0,
        msgCtrlSent : '[Nothing]',
        msgsCtrlSent: 0,
        isLoggedOn  : false,
        userId      : null,
        userPw      : null,
        inputId     : '',
    }, // --- 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: {
        increment: function(event) {
            console.log('Button Pressed. Event Data: ', event)
            // Increment the count by one
            this.counterBtn = this.counterBtn + 1
            var topic = this.msgRecvd.topic || 'uibuilder/vue'
            uibuilder.send( {
                'topic': topic,
                'payload': {
                    'type': 'counterBtn',
                    'btnCount': this.counterBtn,
                    'message': this.inputText,
                    'inputChkBox': this.inputChkBox
                }
            } )
        }, // --- End of increment --- //
        doLogon: function() {
            uibuilder.logon( {
                'id': this.inputId,
            } )
        }, // --- End of doLogon --- //
        doLogoff: function() {
            uibuilder.logoff()
        }, // --- End of doLogon --- //
        // return formatted HTML version of JSON object
        syntaxHighlight: function(json) {
            json = JSON.stringify(json, undefined, 4)
            json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
            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)
    },
    /** 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
        app.player = videojs('video-player')
        console.log(app.player)
        // If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
        // newVal relates to the attribute being listened to.
        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.payload.src ) {
                app.player.src(msg.payload)
                app.player.ready(function() {
                    app.player.play();
                })
            }
        })
        //#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 --- //
// EOF
And in Video-Player.vue:
<template>
    <div>
        <video ref="videoPlayer" id="video-player" class="video-js"></video>
    </div>
</template>
...
As you can see, no more my-video
But still, I get the same error.
I just don't get how to inject <video> options from NR.
Would you or @TotallyInformation please show it to me?
One way to control the <video-player :options="videoOptions"/> which is a sub-component to the main Vue app is to give it a ref (reference) so you can select and then control that element.
 <video-player ref="myVideo" :options="videoOptions"/>
Then you can comment out the lines // app.player = videojs('my-video') as these were used for creating a video player for the  <video  id="my-video" ... example.
Now for accessing and controlling the vue component player modify the lines in uibuilder.onChange ..
uibuilder.onChange('msg', function(msg){
            console.info('[indexjs:uibuilder.onChange] msg received from Node-RED server:', msg)
            console.log("myVideo", app.$refs.myVideo.player)   // log the nested player
            let myVideo = app.$refs.myVideo.player  // save the nested player in variable 
            app.msgRecvd = msg
            app.msgsReceived = uibuilder.get('msgsReceived')
            
            if ( msg.payload.src ) {   
                myVideo.src(msg.payload)   // change src for player
                myVideo.ready(function() {
                    myVideo.play();   // play
                })
            }
        })
Thank you very much @UnborN !
As I said, I'm learning Vue using uibuilder 
You spotted on the mechanic that is still blurry for me.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.