0

I have a page containing multiple HTML5 videos with different captions (webvtt). The video controls are hidden. I have a button «add subtitles» with the ID #check. If the user checks this button, ALL videos should display the captions, and if unchecked, the captions should be hidden. What I have so far:

Hide captions by default:

var video = document.querySelector('.video');
var tracks = video.textTracks;
var track = tracks[0];

$(document).ready(function() {
  track.mode = 'hidden';
});

If button is checked/unchecked, show/hide captions:

$(function() {
  $('#check').click(function() {
    if($(this).is(':checked')) {
      track.mode = 'showing';
    }  else {
      track.mode = 'hidden';
    }
  });
});

This works perfectly BUT only for the first video (since tracks[0] only delivers the value of the first track). Is there anything I can do to solve this issue or am I on a completely wrong path?

L. Maher
  • 103
  • 8
  • You should use querySelectorAll and loop through all the videos. Also, if you're already using jQuery why even use querySelector? – powerbuoy Jun 03 '18 at 21:13
  • Thank you! querySelectorAll returns the TypeError "tracks is undefined", unfortunately. – L. Maher Jun 03 '18 at 21:29

1 Answers1

0

You just need to iterate tracks, like this:

$(function() {
  $('#check').click(function() {
    var isChecked = $(this).is(':checked');
    for (var index = 0; index < tracks.length; index++) {
        tracks[index].mode = (isChecked ? 'showing' : 'hidden');
    }
  });
});

EDIT

The reason that only the first is affected is that you are selecting the very first video. Change your first code to:

var video = document.querySelectorAll('.video'); //querySelector selects the first match only
var videoTrackSets = [];
for (var videoIndex = 0; videoIndex < video.length; videoIndex++) {
    videoTrackSets.push(video[videoIndex].textTracks);
}

$(document).ready(function() {
    for (var setIndex = 0; setIndex < videoTrackSets; setIndex++)
        for (var trackIndex = 0; trackIndex < videoTrackSets[setIndex].length; trackIndex++)
            videoTrackSets[setIndex][trackIndex].mode = 'hidden';
});

and change the second code to

$(function() {
  $('#check').click(function() {
    var isChecked = $(this).is(':checked');
    for (var setIndex = 0; setIndex < videoTrackSets.length; setIndex++)
        for (var trackIndex = 0; trackIndex < videoTrackSets[setIndex].length; trackIndex++)
            videoTrackSets[setIndex][trackIndex].mode = (isChecked ? 'showing' : 'hidden');
  });
});
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • Thank you! It still only seems to work for the first video. A console.log(tracks[index]); only returns the track of the first video. – L. Maher Jun 03 '18 at 21:33
  • @L.Maher I have edited my answer, please, let me know if it is more helpful now. – Lajos Arpad Jun 04 '18 at 12:09
  • Thank you so much. It still doesn’t seem to work. Whenever I check the box, the console returns a TypeError "videoTrackSets[setIndex] is undefined". I feel like the problem already lies in the videoTrackSets in the first code. When I do a console.log(videoTrackSets); it returns an array of 9 items (I have 9 videos), but the value of each item is undefined. If I do a console.log(video.textTrack); it returns "undefined". This probably shouldn’t be undefined? Sorry about these questions, I’m new to JS and a lot of it is still a mystery to me. – L. Maher Jun 04 '18 at 13:20
  • @L.Maher indeed, in the first code I have incorrectly used video.textTracks, but video is an array and I should have used video[videoIndex]. I have edited my answer and fix this. Please, let me know if this fixed the issue. I do not have your structure, so I do not have the means to test. Apologies for the mistakes :) – Lajos Arpad Jun 05 '18 at 09:53
  • This works perfectly, thank you so much for your kind help! Much appreciated! – L. Maher Jun 05 '18 at 11:11