How can I reinitialize Video.js with new options when props.options changes in a Vue.js (Vue 3) component using the watch function?
current code:
const videoPlayer = ref<HTMLVideoElement>()
const player = ref<Player>()
watch(
() => props.options,
(newOptions) => {
if (player.value) {
player.value.dispose();
}
nextTick(()=>{
if (videoPlayer.value) {
player.value = videojs(videoPlayer.value, newOptions)
player.value.loop(newOptions.loop)
}
})
},{ deep: true })
it shows :
VideoPlayer.vue:162 VIDEOJS: WARN: The element supplied is not included in the DOM errr in this line
The issue occurs because when calling player.value.dispose()
, Video.js removes the <video>
element from the DOM. Since videoPlayer.value
is referencing that element, it becomes null
, and initializing Video.js again fails.
To fix this, instead of referencing the <video>
element directly, I created a wrapper <div>
(e.g., videoContainer
) as a parent container. Then, whenever Video.js is reinitialized, I dynamically add the <video>
element as its child.
This ensures that the <video>
element is properly recreated before initializing Video.js again.
fixed code:
const videoContainer = ref<HTMLVideoElement>() // ref to parent elem
const player = ref<Player>()
const initPlayer = () => {
if (!videoContainer.value) return
// Remove existing video element if present
videoContainer.value.innerHTML = ''
// Create a new video element dynamically
const videoElement = document.createElement('video')
videoElement.className = 'video-js vjs-youtube'
// Append the new video element to the container
videoContainer.value.appendChild(videoElement)
// Initialize Video.js on the new video element
nextTick(() => {
player.value = videojs(videoElement, props.options)
player.value.loop(props.options.loop)
})
}
// Initialize video.js when the component is mounted
onMounted(() => {
initPlayer()
})
// Watch for changes in the options prop
watch(
() => props.options,
(newOptions) => {
if (player.value) {
// now its remove the dynamically created video elem insted of ref elem
player.value.dispose()
}
// re-initialize of videojs with new opions
initPlayer()
},
{ deep: true }
)
// Destroy video.js when the component is unmounted
onBeforeUnmount(() => {
if (player.value) {
player.value.dispose()
}
})
</script>
<template>
<div ref="videoContainer"></div>//this is the wraper element
</template>