Why don't audio and video events bubble?
The reason why event bubbling exists is solve the ambiguous question of which element is the intended target of the event. So, if you click on a div, did you mean to click the div, or its parent? If the child doesn't have a click handler attached, then it checks the parent, and so on. I'm sure you know how that works.
The reason why audio events don't bubble is because they don't make sense on any other element. There's no ambiguity when you trigger a timeupdate
on an audio element whether it's meant for the audio element itself or its parent div, so there's no need to bubble it.
You can read a fuller history of event bubbling here
Event delegation
Event delegation is still possible by utilizing the capturing phase of the event. Simply add true as the third argument for addEventListener which looks like this:
document.addEventListener('play', function(e){
//e.target: audio/video element
}, true);
Note, that this event doesn't bubble, but goes down the DOM-tree and can't be stopped with stopPropagation
.
In case you want to use this with the jQuery's .on/.off methods (for example to have namespacing and other jQuery event extensions). The following function, taken form the webshim library, should become usefull:
$.createEventCapturing = (function () {
var special = $.event.special;
return function (names) {
if (!document.addEventListener) {
return;
}
if (typeof names == 'string') {
names = [names];
}
$.each(names, function (i, name) {
var handler = function (e) {
e = $.event.fix(e);
return $.event.dispatch.call(this, e);
};
special[name] = special[name] || {};
if (special[name].setup || special[name].teardown) {
return;
}
$.extend(special[name], {
setup: function () {
this.addEventListener(name, handler, true);
},
teardown: function () {
this.removeEventListener(name, handler, true);
}
});
});
};
})();
Usage:
$.createEventCapturing(['play', 'pause']);
$(document).on('play', function(e){
$('audio, video').not(e.target).each(function(){
this.pause();
});
});
JS Events that don't bubble (progress, loadedmetadata, etc)
- You can test it...
readonly attribute boolean bubbles;
check this property of the event.
bubbles of type boolean, readonly
Used to indicate whether or not an event is a bubbling event. If the event can bubble the value is true, else the value is false.
w3 source not w3School... :)
Audio event does not trigger jQuery on play event
Apparently media events( those specifically belonging to audio or video like play
, pause
, timeupdate
, etc) do not get bubbled. you can find the explanation for that in the answer to this question.
So using their solution, I captured the play
event,
jQuery.createEventCapturing(['play']);
jQuery('body').on('play', 'audio', function(){... // now this would work.
JS Bin demo
the code for event capturing( taken from the other SO answer):
jQuery.createEventCapturing = (function () {
var special = jQuery.event.special;
return function (names) {
if (!document.addEventListener) {
return;
}
if (typeof names == 'string') {
names = [names];
}
jQuery.each(names, function (i, name) {
var handler = function (e) {
e = jQuery.event.fix(e);
return jQuery.event.dispatch.call(this, e);
};
special[name] = special[name] || {};
if (special[name].setup || special[name].teardown) {
return;
}
jQuery.extend(special[name], {
setup: function () {
this.addEventListener(name, handler, true);
},
teardown: function () {
this.removeEventListener(name, handler, true);
}
});
});
};
})();
Catching all audio end events from dynamic content in jquery
Try this:
$('audio').on('ended', function (e) {
alert('done');
var endedTag=e.target; //this gives the ended audio, so you can find the next one and play it.
});
Note that when you create a new audio dynamically, you should assign the events. A quick and dirty solution would be:
function bindEvents(){
$('audio').off('ended').on('ended', function (e) {
alert('done');
var endedTag=e.target; //this gives the ended audio, so you can find the next one and play it.
});
}
and run bindEvents whenever you create/delete an audio element.
html5 audio bind timeupdate before element exists
Apparently media events( those specifically belonging to audio or video like play
, pause
, timeupdate
, etc) do not get bubbled. you can find the explanation for that in the answer to this question.
So using their solution, I captured the timeupdate
event,
$.createEventCapturing(['timeupdate']);
$('body').on('timeupdate', '.audioPlayerJS audio', updateTime); // now this would work.
JSFiddle demo
the code for event capturing( taken from the other SO answer):
$.createEventCapturing = (function () {
var special = $.event.special;
return function (names) {
if (!document.addEventListener) {
return;
}
if (typeof names == 'string') {
names = [names];
}
$.each(names, function (i, name) {
var handler = function (e) {
e = $.event.fix(e);
return $.event.dispatch.call(this, e);
};
special[name] = special[name] || {};
if (special[name].setup || special[name].teardown) {
return;
}
$.extend(special[name], {
setup: function () {
this.addEventListener(name, handler, true);
},
teardown: function () {
this.removeEventListener(name, handler, true);
}
});
});
};
})();
Related Topics
Phonegap Inappbrowser Display PDF 2.7.0
Trigger Standard HTML5 Validation (Form) Without Using Submit Button
Angularjs Does Not Load Scripts Within Ng-View
Jquery Mobile - $.Mobile.Changepage Not Loading External .Js Files
How to Read Xml File Contents in Jquery and Display in HTML Elements
Cropping Images in the Browser Before the Upload
Print Specific Part of Webpage
What HTML Tags Support the Onload/Onerror JavaScript Event Attributes
Getting Unparsed (Raw) HTML with JavaScript
How to Solve Uncaught Rangeerror When Download Large Size JSON
How to Get a HTML Element from a String with Jquery
How to Access the Contents of an Svg File in an <Img> Element
JavaScript to Scroll Long Page to Div
How to Find a Parent with a Known Class in Jquery
Switch Statement for Multiple Cases in JavaScript