vue.jsvideo.js

why videojs not re-initialize in vuejs?


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 

Solution

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