How can I capture the 'ended' event from an HTML5 video tag using Ember in a controller?

I am having an issue with an hbs file that contains an html5 video tag:

<video id="externalVideo" controls loop>
    <source src="../assets/videos/test.mp4" type="video/mp4">
    Your browser does not support HTML5 video.
</video>

I am attempting to trigger a specific action when the video ends and handle this event on the template's controller. However, I am struggling to capture the event on the controller. Can anyone provide insight on how to achieve this?

Software Versions:

  • ember-cli: 1.13.8
  • ember: 2.2.0

Answer №1

[edit: Please refer to my other answer for compatibility with non-bubbling events]

There are three options available, ranked from best to worst:

  1. Implementing the
    {{action 'videoEnded' on='ended'}}
    . This will create a standard action that can be utilized in your controller or route's actions: {}.
  2. Incorporating the ended event into the list of events automatically monitored by Ember:

    customEvents: {
      ended: 'videoEnded'
    }
    

    The addition of this customEvents must occur during application creation (in the same location as passing

    rootElement</code). The exact process will vary based on your boot sequence, whether you are using ember-cli, and other factors.</p>
    
    <p>If configured correctly, Ember will listen for <code>ended
    events and search for a function named videoEnded within your views or components.

  3. Manually handling events (recommended only when developing an addon or unable to utilize option 1 or 2).

    init: function () {
        this._super();
        this._videoEnded = this.videoEnded.bind(this);
    },
    registerEvents: Ember.on('didInsertElement', function () {
        this.get('element').addEventListener('ended', this._videoEnded, false);
    }),
    unregisterEvents: Ember.on('willDestroyElement', function () {
        this.get('element').removeEventListener('ended', this._videoEnded, false);
    }),
    videoEnded: function (evt) { Ember.run(function () {
        console.log('Video ended');
    })}
    

    This method may seem a bit messy. In the init section, a bound version of the handler is created so that this retains the correct value upon execution. Subsequently, the event is registered once Ember has established the DOM element, and then unregistered during the teardown process.

    Lastly, the handler is enclosed within a run loop to ensure that Ember can detect property changes and manage triggers and bindings accurately.

Answer №2

After realizing that the ended event does not bubble, I decided to keep my previous answer for reference purposes. This could potentially help others who encounter a similar issue with a bubbling event.

Since the event doesn't bubble, manual handling is necessary. It's akin to option 3) from my earlier response. My recommendation is to encapsulate this behavior into a component:

// custom-video-player/component.js
import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'video',
  attributeBindings: ['autoplay', 'buffered', 'controls', 'crossorigin',
                      'loop', 'muted', 'played', 'preload', 'poster', 'src'],

  init: function () {
    this._super();
    this._events = {};
    Object.keys(this.events).forEach(function (name) {
      this._events[name] = function (evt) { Ember.run(this, this.events[name]); };
    }, this);
  }

  registerHandlers: Ember.on('didInsertElement', function () {
    var el = this.get('element');
    Object.keys(this._events).forEach(function (name) {
      el.addEventListener(name, this._events[name], false);
    }, this);
  }),
  unregisterHandlers: Ember.on('willDestroyElement', function () {
    var el = this.get('element');
    Object.keys(this._events).forEach(function (name) {
      el.removeEventListener(name, this._events[name], false);
    }, this);
  }),

  events: {
    play: function (evt) { this.sendAction('play'); },
    ended: function (evt) { this.sendAction('ended'); }
    // add more if needed
  }
});

To use it, follow this format:

{{#custom-video-player id="externalVideo" controls loop ended='handleVideoEnd'}}
  <source src="../assets/videos/test.mp4" type="video/mp4">
  Your browser doesn't support HTML5 video.
{{/custom-video-player}}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Disabling vertical scrollbar in textarea within Bootstrap modal using CSS, jQuery, and C# in .NET MVC framework

I am passing data to the Bootstrap modal using jQuery from my database. The form values can change from a single row to multiple rows. I do not want a scrollbar, but instead I want the textarea element to automatically adjust its height to fit the content. ...

Implementing multiple filters with jQuery

Make a Selection `<select class="form-control" id="technology"> <option name="sort" value="2g" id="2g"gt;2G</option> <option name="sort" value="3g" id="3g"&g ...

Scrollable content with sticky positioning using CSS3 and JavaScript

I successfully implemented a sidebar using the position: sticky property and it is functioning perfectly. To identify colors in the following text, refer to the script below. When scrolling, the black area remains fixed while the green area sticks to its ...

json array: Tips for adding elements to a new array

In order to achieve my goal, I am looking to create a JSON array structure similar to the one shown below: var args = [{ name: 'test', value: 1 }, { key: 'test2', value: 2}]; How can I modify the code snippet provided below to generat ...

Unable to trigger onSelect event on the datepicker component

Whenever a date is chosen, I need to trigger a javascript function. Here is the javascript code: $(document).ready(function(){ var date_input=$('input[name="date"]'); //our date input has the name "date" var container=$('.bootstrap- ...

Is React failing to identify parameters?

working on my react project, I have an App component which is responsible for rendering multiple child components. Here's how it looks: App render() { return ( //JSX inside <BrowserRouter> <div> <Heade ...

One Background Image Serving Multiple Divs

Can you use one image (PNG or SVG) as the background for multiple divs? Take a look at the images below to see how it could work. And if the screen width gets smaller and the divs stack up vertically, is there a way to change the background accordingly? D ...

Capture the 'value' of the button when clicked using ReactJS

I'm generating buttons dynamically using the map function to iterate through an array. Each button is created using React.createElement. ['NICK', 'NKJR', 'NKTNS'].map(function (brand) { return React.createElement(' ...

Discovering if an array includes a particular value in JavaScript/jQuery

Is there a way to check if the list with the class .sidebar contains an item with data-id="1"? <ul class="sidebar"> <li data-id="1">Option 1</li> <li data-id="2"> Option 2</li> <li data-id="3"> Option 3</li&g ...

steps to create a personalized installation button for PWA

Looking to incorporate a customized install button for my progressive web app directly on the site. I've researched various articles and attempted their solutions, which involve using beforeinstallprompt. let deferredPrompt; window.addEventListener(& ...

Is it safe to securely store connection credentials in javascript?

I am currently working on developing a web chat app for a Minecraft server using this API. However, the demo script I am referring to displays connection information in plain text, making it easily visible to any client's computer. Is there a way to s ...

What's the most effective method for implementing a stylesheet through Javascript in a style switcher?

I've been tackling the challenge of creating a style switcher for my website. Through utilizing .append() and if and else statements, I managed to make it work successfully. Take a look at the code below: HTML <select name="active_style" id="lol" ...

Parsley JS: A Solution for Distinct IDs

I have a form that contains multiple select boxes, and I need to ensure that no two select boxes have the same value selected. In simpler terms, if select box 1 is set to value 2 and select box 4 is also set to value 2, an error should be triggered. While ...

Package.json failing to enable NodeJS unsafe-perm functionality

Attempting to execute a npm install command with a preinstall script in my package.json. Despite being aware of it being considered an antipattern, I need to run certain scripts as root. The approach works when adding a .npmrc file with the content unsafe ...

An alternative solution for supporting Edge Chromium is utilizing synchronous AJAX requests within the beforeunload event

While attempting a synchronous ajax request during the beforeunload event, I encountered an error stating that synchronous ajax requests are not supported in chromium browsers during page unload events. I am seeking alternatives for making a synchronous a ...

What is the best way to reference an i18n entry within .json files?

I am in the process of creating a user interface using SAP UI5 and my goal is to make all text elements internationalized. Below is a snippet of my view in .xml format where I successfully retrieve text in different languages using placeholders enclosed i ...

What is the best way to implement a constant countdown timer in JQuery that remains unaffected by page refreshes?

I have implemented a time countdown feature in my web app using this jQuery plugin. However, I am facing an issue where the countdown starts from the beginning every time the page is refreshed. I want the countdown to remain consistent for a month (30 days ...

Pressing the enter key in an AngularJS form does not trigger submission

Having trouble with a login form that won't submit when the user presses enter. While the form works fine when the "Login" button is clicked, hitting enter doesn't trigger submission and leads to some unexpected behavior: The ng-submit associat ...

Is it possible to change cases within a switch statement after one case condition has been satisfied?

I am currently working on implementing a game that involves rolling dice in Javascript/jQuery. The game has different "Phases" that the player must complete one by one without any interference from previous phases. The goal is to smoothly transition betw ...

Crafting a custom React Native button component with an asymmetrical design

I am trying to design a unique custom react native button that is slanted on one side. Despite reading numerous articles, I haven't found a solution that meets my specific requirements. Below are examples of how I would like the buttons to look – on ...