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.