My goal with this was to wrap the terrible YouTube Embed API in a Stimulus controller that would allow me to access the underlying API while providing some convenience methods. One key outcome is that the controller emits youtube events which contain the current position in the video. This means that other code can now respond to the position you are at in the video.
<div data-controller="youtube" data-youtube-code-value="Lo_1pyQ7xvc">
<button data-action="youtube#play">Play</button>
<button data-action="youtube#pause">Pause</button>
<button data-action="youtube#stop">Stop</button>
<br>
<div data-youtube-target="frame"></div>
</div>The buttons and br are not neccessary, they just help show off the functionality.
When the controller connects, data-duration, data-time and data-state attributes will appear on the controller element. This is really handy if you're using this element to initiate a Reflex, as all of the attributes will be automatically sent to the server as part of the Reflex.
If you want to send the YouTube instance commands, you'll need a DOM element reference to the container div. I'm going to assume that you have that, and that it's available to you as $0.
$0.addEventListener('youtube', e => console.log(e.detail.time))
$0.youtube.player.mute()The controller element emits one non-bubbling youtube event every second that the video is playing.
The controller element has a youtube accessor which is a reference to the internal state of the Stimulus controller.
I did not want to attempt to exhaustively replicate the functionality of every getter and setter offered by the YouTube API. If you want to mute() or unMute() you can access the underlying YouTube API via the player accessor.
You must specify a data-youtube-code-value attribute. data-youtube-width-value and data-youtube-height-value are optional.
- play()
- pause()
- stop()
- seek(seconds)
- player // reference to wrapped YouTube API instance
- time // current position in the video, as an integer representing seconds
- duration // number of seconds total in the video
- state // see states below
- loaded // percentage of video that has been downloaded / buffered, expressed as a float from 0 to 1
If you want to convert loaded to a percentage, multiply it by 100 and parseInt().
-1 (unstarted) 0 (ended) 1 (playing) 2 (paused) 3 (buffering) 5 (video cued)
Hi!
I am getting this error in the console ;(
`[stimulus.js? [sm]:1718 Error connecting controller
TypeError: Cannot read properties of undefined (reading 'destroy')
at extended.connect (youtube_controller-17dfa670e4c222bf1c314496a30f203987acc2375be746b3ee027d6f9b8bb39c.js:20:70)
at Context.connect (stimulus.js? [sm]:1127:29)
at Module.connectContextForScope (stimulus.js? [sm]:1318:17)
at stimulus.js? [sm]:1642:42
at Array.forEach ()
at Router.connectModule (stimulus.js? [sm]:1642:16)
at Router.loadDefinition (stimulus.js? [sm]:1605:14)
at stimulus.js? [sm]:1701:29
at Array.forEach ()
at Application.load (stimulus.js? [sm]:1699:21)
{identifier: 'youtube', controller: extended, element: div}](url)`