I want to update the source tag in a HTML5 video element so that when I click a button, whatever's playing switches to a new video.
I have a Clip component that returns an HTML5 video element, with the source URL provided via props.
function Clip(props) {
return (
<video width="320" height="240" controls autoPlay>
<source src={props.url} />
</video>
)
}
I also have a Movie component, which contains multiple URLs, each corresponding to a section of the movie. It also contains a position attribute, which acts like an iterator by remembering which section is currently playing.
class Movie extends Component {
constructor() {
super();
this.state = {
sections: [
'https://my-bucket.s3.amazonaws.com/vid1.mp4',
'https://my-bucket.s3.amazonaws.com/vid2.mp4'
],
position: 0
};
}
render() {
const sections = this.state.sections
const position = this.state.position
return (
<div>
{position}
<Clip url={sections[position]} />
<button onClick={() => this.updatePosition()}>Next</button>
</div>
)
}
updatePosition() {
const position = this.state.position + 1;
this.setState({ position: position });
}
}
The Movie component renders a Clip component and a "Next" button. When the Next button gets clicked, I want to update the position attribute and re-render the HTML5 video element using the next URL from sections.
As of now, when I hit Next the HTML5 video source tag updates, but the element continues playing the video from the previous URL. Can anyone help me figure out how to reset the video element?
Update: I created a JSFiddle, which you can see here.
Update 2: Updating the src attribute on the video element works!
Quick and dirty awnser: Add a key prop to <Clip> or <video>, e.g.:
function Clip({ url }) {
return (
<video key={url}>
<source src={url} />
</video>
);
}
Recommended awnser: Trigger a load event for the video element whenever there's a new URL, e.g.:
function Clip({ url }) {
const videoRef = useRef();
useEffect(() => {
videoRef.current?.load();
}, [url]);
return (
<video ref={videoRef}>
<source src={url} />
</video>
);
}
Explanation: The video initially doesn't change because in essence you're only modifying the <source> element and React understands that <video> should remain unchanged, so it does not update it on the DOM and doesn't trigger a new load event for that source. A new load event should be triggered for <video>.
The dirty answer works because when you change the key of a React element, React understands that's a whole new element. It then creates a new element in the DOM which naturally will have its own load event triggered on mount.
Changing the src of <source /> doesn't seem to switch the video for some reason. This isn't a react issue I don't think. Probably just how <source /> works. Maybe you have to call .load() on the element again. But it's just easier to set it directly on the element itself.
See the comment to the top answer: Can I use javascript to dynamically change a video's source?
You can set src directly on element instead:
function Clip(props) {
return (
<video width="320" height="240" src={props.url} controls autoPlay>
</video>
)
}
Bind the URL in the src property of Video tag and not Source Tag
<video autoplay loop muted playsinline="true" webkit-playsinline="true" [src]="videoSrc" type="video/mp4">
Add a parent div to second video
My code:
{isMobile ? (
<video
autoPlay={true}
loop
className="moviles"
muted
playsInline
poster="/totto/kids.png"
>
<source src="/totto/losmoviles.webm"></source>
<source src="/totto/losmoviles.mp4"></source>
</video>
) : (
<div>
<video
autoPlay={true}
loop
className="moviles2"
muted
playsInline
poster="/totto/portada.jpg"
>
<source src="/totto/moviles.webm"></source>
<source src="/totto/moviles.mp4"></source>
</video>
</div>
)}
You can use the key attribute :
<video key={videoUrl} autoPlay width="100%">
<source src={videoUrl} type="video/mp4"></source>
</video>
If the video's key attribute change, the video component will be re-mounted
Related
I was thinking of having a button which calls a drawing component so I can draw on top of the video player component.
const VideoPlayer = ({selectedVideo}) => {
return(
<div className="App">
<video key = {selectedVideo} width="950" height="500" controls>
<source
key= {selectedVideo}
src={selectedVideo}
type="video/mp4" />
</video>
</div>
);
};
export default VideoPlayer;
I was thinking of writing something similar to this:
I want to draw (using html5 canvas) inside video in react but with the ability to having drawing enabled or disabled with a button press and that it stays within the boundaries of the video player. How do you suggest I go about doing this?
I'm sorry that my english is not very good, I searched for many methods I could find on the Internet, but they were all unsuccessful.
My idea: When the website is opened, a video will be automatically played (A). When the mouse clicks on the video (rather than some buttons), video A will be replaced with video B, and keep the same size and format, and be on the same web page. And when the mouse is clicked again, video B is changed to video A again.
This is the code I tried but it failed:
function setVideo() {
document.getElementById("video-01").src="demo/2.mp4";
}
<div class="video" id="video-one" οnclick="setVideo()">
<video id="video-01">
<source src="demo/1.mp4" type="video/mp4"/>
</video>
</div>
I haven't learned how to program, so I don't know how to do it. I have tried to use in HTML to link to another video, but this will change the style of the page.
Can you help me please?
Like this?
const videoA = 'https://media.istockphoto.com/videos/attractive-woman-blogger-speaks-about-professional-voice-over-and-video-id1253606799'
const videoB = 'https://media.istockphoto.com/videos/aerial-shot-flying-along-road-with-driving-vehicles-trucks-and-cars-video-id1251170644'
document.querySelector('video').addEventListener('click', (evt) => {
const currentVideo = evt.target.getAttribute('src')
if (currentVideo === videoA) {
evt.target.setAttribute('src', videoB)
} else {
evt.target.setAttribute('src', videoA)
}
})
<video autoplay muted width="480" height="320" src="https://media.istockphoto.com/videos/attractive-woman-blogger-speaks-about-professional-voice-over-and-video-id1253606799"></video>
I have a react component subclass which renders a video:
render() {
return (
<video id="video">
<source src={this.props.src} type="video/mp4" />
</video>
);
}
I need to attach an event listener for the error event to the video source some time after it's created but before it's rendered. How do I do this?
You probably don't want to dynamically attach the event. Instead just have the event on it and have some if condition in the event.
If you really want to attach it dynamically then do:
<video id="video" onError={this.state.someCondition ? myFunc : null}>
<source src={this.props.src} type="video/mp4" />
</video>
Or use this.props.someCondition if you are passing the condition down from the parent.
If your condition isn't in the state or props then it will need to be.
If this isn't what you want then post more context please. Sounds like you want the componentWillMount function
I have an slider of videos, I want to autoplay when visible and autostop when not visible. The visible video at the moment of stay visible has a class (active) that identifies it.
<video class="item active" controls autoplay poster="" width="640" height="360">
<video class="item" controls autoplay poster="" width="640" height="360">
<video class="item" controls autoplay poster="" width="640" height="360">
How can I do that?
You can manipulate the states of video with javascript.
For playing for example you can select the video tag that have class active and play it:
document.querySelector('video.active').play();
For any other video tags you can just pause them with this code:
var videos = document.querySelectorAll('video.item');
for(var i = 0; i < videos.length; i++) {
videos[i].pause();
}
You will need to make this manipulation on click, or on slide change, and also take note that first you will need to stop all videos then just play the video with active class.
I trigger the events on my slider when translates an initialize a slide an then execute these functions:
When translate:
function(){
$('.item').find('video').each(function(){
this.pause();
});
When initialize a new slide (to automatically play it):
function(){
$('.active').find('video').each(function(){
this.play();
});
That solved my problem.
Try this:
$("video").prop("volume", 0.3).click(function() {
this[this.paused ? "play" : "pause"]()
});
So I only want to access the play button of the video controls, no action when pressing the track bar or volume. I want something like this but with html5 video http://flash.flowplayer.org/demos/installation/multiple-players.html
jQuery(document).ready(function() {
$('.vids').click(function(){
$('.vids').each(function () {
this.pause();
});
});
});
<video controls="controls" class="vids" id="1">
<source src ....>
</video>
<video controls="controls" class="vids" id="2">
<source src ....>
</video>
....
So now all videos stop except the one I clicked but when I press the trackbar or volume, it also stops. Any solutions without making my own controls or making use of another videoplayer? I found different solutions but not as I want :S
I think you have to target the current item which you are clicking so that the clicked target get the command to process to do this try this one and see if this works for you:
$('.box').click(function(e){
$(e.target).pause();
});