video.js
video.js copied to clipboard
Provide an option to keep dom element when dispose
Hi, I want to know could we add an option to keep the dom element when dispose is called?
My dom is generated by a template system, and then bind videojs to the video tag. Now I want to do some dynamic loading of the data, so I have to remove the videojs object, and create videojs object again, so the side effect of videojs makes this impossible. Because my tag generated by the template system disappear.
Not only this issue, but also the other one. https://github.com/videojs/video.js/issues/4878
Could we provide an option to let this possible?
This is a bit tricky because we don't really store the original tag. The main thing we could probably do is restore a video element with the id of the player. It also gets a bit tricky because we have 3 embed options currently and technically, an audio element is available as well. And we probably shouldn't store the original embed as a string to re-use on dispose.
However, I'm thinking that for your situation, the template system should probably generate a container and the javascript should place the video player inside that container.
@videojs/core-committers thoughts on this feature request?
I'd like to add another use-case to the feature request.
Summary:
- On mobile web, I have a
<video>tag which is inserted into the dom based on a user's click. - I would like to display a playlist of videos to the user.
- Some of the videos in the playlist will be displayed with videojs but some will not.
- Only one video will be "active" at a time.
- I would like to use the same
<video>tag across all those videos, because the browser will have "blessed" it as a video the user opted in to (for audio).
Here is a sample application, https://jsfiddle.net/hmjr001r/46/, showing:
- Insert a bare bones
<video> - Load a non-videojs video into that
<video> - unload it
- Load a videojs video into that
<video> - dispose it
- Load a non-videojs video into that
<video><==== issue
Notes: I am already using the player div ingest (data-vjs-player), so that the initial <video> tag stays in the dom as I initialize it into a videojs player. Which was super helpful, :).
Similar threads: #4397, #1023
The core of the conflict is that video.js assume the tag is one time used. But the fact is that modern front-end is build upon the responsive idea.
video.js heavily build on top of the side effect , like change the tag id, remove the tag after videojs clean.
Those are not good practice. User will assume when an object clean, the environment would be recover to previous status, the side effect breaks the agreement.
It works fine before because less responsive environment it met, now when all the responsive components has the re-entry logic existed, keep yourself side-effect free is more and more import to work with other components.
@gkatsev Dear developers, could you give some thoughts here?
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Running into problems similar to those of the OP. Would love to see a solution here :). Keep up the good work!
I'm also running into this issue with videojs lately. Specifically my use case is with that of elementor.
To anyone coming here from google searching for how to get this to work with React, this was the solution I ended up with. I was trying to figure out how to quickly change the source for a videojs player and dispose wasn't working
function VideoViewer(props: Props) {
const videoRef = useRef();
const [requireRedraw, setRequireRedraw] = useState(false);
// Handle any other effects separately to avoid re-mounting the video player when props change
useEffect(() => {
const videoNode = videoRef.current;
const videoJsOptions = {
...VIDEO_JS_OPTIONS,
sources: [
{
src: source,
type: contentType,
},
],
};
let player;
if (!requireRedraw) {
player = videojs(videoNode, videoJsOptions);
}
return () => {
if (!player) {
return;
}
// Video.js has a player.dispose() function that is meant to cleanup a previous video
// We can't use this because it does some weird stuff to remove the video element from the page
// This makes it really hard to use because the ref we keep still thinks it's on the page
// requireRedraw just makes it so the video component is removed from the page _by react_
// Then it's set to false immediately after so we can re-mount a new player
setRequireRedraw(true);
};
}, [videoRef, source, contentType, hasFileInfo, setRequireRedraw, requireRedraw]);
useEffect(() => {
if (requireRedraw) {
setRequireRedraw(false);
}
}, [requireRedraw]);
return (
<div>
{!requireRedraw && (
<div data-vjs-player>
<video ref={videoRef} className="video-js" />
</div>
)}
</div>
);
}
Big thank to @seanyesmunt <3
Is there any update to this issue of using dispose? I followed the DOCS on using videojs is a modal to show/hide video, but dispose STILL removes the video element from the DOM.
How about something that will just disconnect the player or stop the stream when the modal is closed? Honestly, I should only need to create the player once, then set the src when needed. The player shouldn't have to worry about being visible or not (that's up to the modal[jQuery]).
I might just have to switch back to hls.js even though it doesn't have nice styling.
Recently started using videojs but also ran into this issue already. Would be really nice to have a cleanup function that doesn't remove the video element.
I recently also ran into this problem, my fix was the following using React 17.0.1 and a functional component, this works in my React App, so hopefully somebody else has use of it. Better versions/revisions are always appreciated.
import React from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
export const VideoJS = ( props ) => {
const videoRef = React.useRef(null);
const { options } = props;
// making the video Element a seperate React Component
// it will get re-added/re-rendered every render of it's parent Component
// fixes the dispose() method removing the element from DOM
const VideoHtml = ( props ) => (
<div data-vjs-player>
<video ref={videoRef} className="video-js vjs-big-play-centered" />
</div>
);
React.useEffect( () => {
const videoElement = videoRef.current;
let player;
if( videoElement ) {
player = videojs( videoElement, options, () => {
console.log("player is ready");
});
}
return () => {
if( player ) {
player.dispose();
}
}
}, [options]);
return (<VideoHtml />);
}
export default VideoJS;
Also ran into this problem too, and hope videojs provide an option to keep dom element when dispose
This works for me:
import React, { useEffect, useState } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
export const VideoJS = ({ videoJsOptions, ...props }) => {
const [videoContainerEl, setVideoContainerEl] = useState(null);
useEffect( () => {
if (!videoContainerEl) return;
videoContainerEl.innerHTML = `
<div data-vjs-player>
<video class="video-js vjs-big-play-centered" playsInline />
</div>
`;
const videoEl = videoContainerEl.querySelector('video');
const player = videojs(videoEl, videoJsOptions);
return () => {
player.dispose();
}
}, [videoJsOptions]);
return <div {...props} ref={setVideoContainerEl} />;
}
export default VideoJS;
Hi all, I have just published version 3.0.0 of my react-hook-videojs package that should support React 18 Strict Mode. It required a fair bit of DOM manipulation to undo the DOM destruction caused by videojs dispose. Let me know if it works for you! https://github.com/jimmycallin/react-hook-videojs/