# Blazor and Media events - Hard to handle?

## Preface

I saw some chat recently on the  [Blazor Gitter Channel](https://gitter.im/aspnet/blazor) asking about binding to events on the html5 `video` tag. It seems this person was not alone - others had similar problems - the events you subscribe to in Blazor are just not firing. 

![Hello, can anyone point out the very obvious mistake I must be making? I'm trying to get some events to trigger when a Video is played. I'm using the standard html5 &ltvideo&gt tag. I can see all the events created in Chrome / Edge. But I can't get them to fire. The onclick one is working - but nothing else.](https://cdn.hashnode.com/res/hashnode/image/upload/v1597346640992/h8fjJPyTf.png)

I decided (I like a challenge) to investigate - read on to find out more.

TLDR; I made a Blazor component to overcome the problem. [Blazored.Video](https://www.nuget.org/packages/Blazored.Video/)

## Why do these events not work?

Some html events do not bubble up the dom hierarchy, so they never fire at the document level, and Blazor attaches it's event listeners to the document.

Blazor maintains a list of events that do not bubble so that it can register event listeners for the  [capture phase](https://www.w3.org/TR/DOM-Level-3-Events/#event-flow)  on those events.

> abort, blur, change, error, focus, load, loadend, loadstart, mouseenter, mouseleave, progress, reset, scroll, submit, unload, DOMNodeInsertedIntoDocument, DOMNodeRemovedFromDocument

Notably absent from this list are the HTMLMediaElement events:

> canplay , canplaythrough , durationchange , emptied , ended , loadeddata , loadedmetadata , loadstart , pause , play , playing , progress , ratechange , seeked , seeking, stalled, suspend, timeupdate , volumechange , waiting 

This means any attempt to bind to these events does not work as Blazor does not register for the capture phase on these events.

## What is the solution?

The real fix is to get the Blazor team to add them to the list, but this hasn't had a lot of community push, in fact the last  [issue raised](https://github.com/dotnet/aspnetcore/issues/20983)  about it was closed due to lack of activity.

Maybe someone could do this during one of the  [Blazor Sprints](https://github.com/dotnet/aspnetcore/wiki/Blazor-Development-Sprints) 

## How about a workaround?

Luckily it's not that hard to work around this with a new Video component.

It's long been known that you can trigger an html event in JavaScript land using dispatchEvent and (as long as it bubbles) Blazor will catch it and process it like any other.

`el.dispatchEvent('play', { bubbles: true })`

One problem is we don't want to write all those bits of code to capture and rethrow specific events because it's a lot of work to do that and prevent event loops. 

Could we use an existing one that bubbles on the `video` element? 

If you noticed, there is no `change` event on a media element, like `video`, so can we use that?

Yes, we can dispatch a `change` event on the video element, but what use is that when we want to subscribe to the `play` or `timeupdate` events?

The answer lies in the property `value`, which the `change` event passes back to Blazor/C#.

What if we create and populate a `value` property on the `video` element just before we dispatch the `change` event? We could populate it with the name of the event we are capturing.

### Wait a minute, can we add value as well?

Here's a thought - what if we populate the new `value` with actual data along with the event name?

``` JS
var data = { currentTime: el.currentTime }
el['value']=JSON.stringify({ event: 'play', payload: data })
el.dispatchEvent('change')
```
Now, we have a way to capture not only the non-bubbling event, but also to return an object with useful information from the `video`.

## Summary

After doing this investigation, I realised it was workable in quite a small amount of code to wrap the html5 `video` element in a Blazor component that allows you, as a developer, to subscribe to any of these non-bubbling events and return arbitrary slices of data for each one.

You can find the resulting component in the  [Blazored](https://github.com/Blazored/Video)  components - it is a little more complicated than I laid out here, but the method is pretty much as described.


