The Easy Part

When using an html video element, it is rather straight forward to change its source. The value of the src attribute needs to be changed and then the load method called (and eventually the play method, to start the video playback).

Video element

<video id="video" controls="true" src=""></video>

Changing video src attribute

var src = 'video_file_url',
    video = $('#video')[0];
video.src = src;
video.load();

Reset the source

With more complex cases, there are probably thousands of reasons to do it differently. For example, the whole video element can be replaced:

Replacing whole video element

<div id="video">
    <video controls="true" src=""></video>
</div>
// Create new video element
var src = 'video_file_url',
    prevVideo = $('#video > video')[0],
    $video = $('<video/>'),
    video = $video[0];

// Replace old video element
$('#video').html(video); //method 1
$('#video').empty().html(video); //method 2
$('#video').find('video').remove().end().html(video); //method 3

// Set new source
video.src = src;
video.load();

Just one more thing needs to be done - the source of the previous video element should be reset.

Reseting src attribute

// Reset
prevVideo.src = null;
prevVideo.load();
// Set new source
video.src = src;
video.load();

Death by a thousand videos

The problem: Video elements detached from dom can still play and buffer video files. When a video element is replaced or even removed before being replaced… well, it shouldn’t be there, and I am not sure in what state it is in. Is it detached, or waiting for some dom garbage collector?

The thing is, the video element is still there and is still buffering video (but not playing, so here is the difference between being detached and this unknown state). If you replace a video element multiple times, you end up with the browser (in my case Chrome) downloading all videos at the same time, hence starting to slow down. That’s why resetting the source is important, and it is basically the solution to this problem.

You can experience this case on the jsfiddle demo here (check the Network tab in dev tools):

Here is how it should look in the dev console:

Normal (proper) loading

Parallel loading