In Chrome 31 on Windows 7 and Linux (Ubuntu 13.10) an event handler on a video element, registered for canplay (and oncanplay, just to make sure) never fires. When I inspect the DOM node, there's no oncanplay property. The spec says it should exist. Does anyone have any idea when, or if, Chrome might support this event?
Chrome does support the canplay event. You're not seeing it because the inspector only shows those properties that are on all elements, not just media elements. It also does not show loadedmetadata, durationchange, etc. but Chrome definitely supports those.
I haven't seen your code, but I would guess that a likely reason that you would see the event fire (assuming you're listening for it correctly) is that you've missed the event. Unless you're skipping around the video quite a bit, canplay will only fire one time. So if the event fires before you attach the listener, it's too late.
Instead, you can check the state, like so...
//assume you've already set up the video variable to point to your video element
if (video.readyState >= video.HAVE_FUTURE_DATA) {
console.log('video can play!');
} else {
video.addEventListener('canplay', function () {
console.log('video can play!');
}, false);
}
(Depending on what you're trying to accomplish, you may want to attach the event listener either way. The video's readyState can revert back if you run out of buffered data, and canplay might fire again later.
Related
Here's something odd, that I felt sure was working in earlier mobile browsers: In Chrome on Android, and Safari on iOS, it seems the touchstart event is fired after the click event, not before. When did this change?
A simple example:
jQuery(function($) {
var touched = false;
$('#clicky').on('touchstart', function(evt){
touched = true;
evt.preventDefault();
})
.click(function(){
if (!touched) {
alert("somehow touch didn't fire")
}
});
})
Run this fiddle, and you'll see the alert can pop up on Android and iOS, when it should actually never show!
http://jsfiddle.net/quxnxu7d/2/
I ran it through Chrome on Android and it worked as you expected for me. I added an alert to the touchstart handler and it fired to be sure that it was firing first and it did.
Take a look at the touch events mdn article. The article specifically mentions:
calling preventDefault() on a touchstart or the first touchmove event of a series prevents the corresponding mouse events from firing
Click is a mouse event so it "should" work as you expect (and it was working for me). I'd verify that the events are indeed running out of order (use console.log() instead of alert()) on your target browsers. If they are, which is perfectly possible with less than perfect browsers/specs, try using a different mouse event like mouseup. My guess is that you'll be able to find an event that works consistently.
Good luck!
Have you tried using mousedown instead of click? That way you should get different events for touch and click without any double firing. You will also likely need to use keydown to keep this site accessible.
There is a 300ms delay between a physical tap and the firing of a click event on some mobile browsers (e.g. iOS Safari)
I ran into the same issue and FastClick jQuery plugin fixed it for me
Have a look FastClick
When I try to inspect the touchmove event in this jsbin demo it only triggers once in Chrome and Opera for Android, and immediately after that, it triggers a touchcancel event, instead of continuing to trigger touchmove events?
Based on both the W3C specs, and the behaviour of the touchmove event in both Firefox for Android and Android's default browser, it seems to me that the way the touch events are supposed to work is that the touchmove event keeps triggering while the touch is still on the page. After trying to test in this jsbin though, I got the following log messages:
touchstart event; starting on (140,197) on the screen, or (381,536) on the page.
touchend event; starting on (undefined,undefined) on the screen, or (undefined,undefined) on the page.
touchstart event; starting on (181,137) on the screen, or (492,372) on the page.
touchmove event; starting on (182,153) on the screen, or (495,416) on the page.
touchcancel event; starting on (undefined,undefined) on the screen, or (undefined,undefined) on the page.
This is what happened when I first tapped the screen (shown via a touchstart and touchend), and then dragged the screen (touchstart, touchmove and touchcancel). Going by the same specs mentioned above, the touchcancel event should only run when something interferes , such as the browser interface (if I understand that correctly).
Since I was simply sliding my finger over the body, without leaving the window at all, I am really puzzled by this, so would anybody know why this is happening?
I am getting this unexpected result in Chrome 32 and Opera 19 for Android.
Turns out the problem here was simply the fact the event handler didn't have an event.preventDefault() in it, so the original action still executed, which apparently interrupted the touch event. To fix this, simply add e.preventDefault() in the current event handler function to cancel the current event, and make it work as expected in Chrome and Opera too.
Working demo.
I have a standalone web application that used to work fine with iOS 6.
With iOS 7 I noticed that there is a significant delay (several seconds) in firing the javascript touchend event after a finger swipe. The behavior is not consistent, sometimes the first swipe generates the event immediately and only the following ones are delayed.
Is this a known issue and/or there is a workaround?
Thanks.
I was experiencing this same problem with an HTML5 game I'm developing. Sometimes the touchend would seem to fire immediately, and other times there would be a delay of several seconds before it fired.
I stumbled upon this post reminding me of the setTimeout 0 trick for pushing a block of javascript onto the queue for later processing. I was doing a bit of "heavy-lifting" (some DOM manipulation) inside the touchend event handler, and this appeared to disrupt its firing.
I wrapped the code inside my touchend handler with a setTimeout, and that eliminated the delay:
$(document).on('touchend', function (e) {
setTimeout(function(){
//do stuff here...
}, 0);
});
Safari on iOS 7 and HTML5: problems, changes and new APIs: http://www.mobilexweb.com/blog/safari-ios7-html5-problems-apis-review
iOS 7.1 seems to fix this issue; touchend events fire properly (even without the zero timeout)
I'm building a jQuery plugin for managing HTML5 videos. I'm trying to capture the canplay and canplaythrough events. In Chrome, the event is fired without problem. In Firefox, sometime it's triggered, sometime it's not.
I'm simplifying my code a little here:
$('#my_video').on('canplay canplaythrough', function(){
console.log('canplay event fired');
});
I also tried with the native javascript .addEventListener() and it's not working.
Any idea why the event is not called on Firefox and how to fix that?
NOTE: Please do not tell me to use one of the already available plugins like jplayer and video-js, I know that they exist and work well, but I have to build an in-house solution.
The problem is that your video element has triggered the canplaythrough event before you registered the event handler.
As you pointed out in your own answer, you can put your scripts in the <head>, but this is bad for your page performance.
A better way to fix your problem is to check the readystate attribute and execute your function manually in that case:
var $video = $('video'),
videoElement = $video[0];
$video.on('canplaythrough', callback);
// If the video is in the cache of the browser,
// the 'canplaythrough' event might have been triggered
// before we registered the event handler.
if (videoElement.readyState > 3) {
callback();
}
The most likely reason you're seeing this probably has to do with timing issues. You stated in your accepted answer that putting jQuery into the head rather than the footer solves the problem. This tells me that the issue is DOM parsing and script execution order. The most likely culprit is that the "canplay" and "canplaythrough" events were being fired before jquery and your page script were parsed and the event handlers added - but only sometimes, depending on network traffic and load times. By putting the script in the head, you forced your event binding to occur before the DOM elements were created, thereby ensuring that you didn't miss any events.
As an aside, the performance benefits of putting script elements at the bottom of the page are debatable. If you really want to tweak page performance, use something like LABjs to manage parallel script loading.
In my case, this was determined by the preload attribute specified for the element. I did not have it specified at all, so different browsers were choosing to do different things.
Once I specified preload="auto", the on("canplay") event handler worked fine/as expected.
Even if my question didn't get any attention whatsoever, I think it's a good idea to give an explanation for people who may stumble on this in the future...
The problem is really weird: if the jQuery core is included in the footer, some of the video events do not work. If the jQuery core is included in the head of the document, all events are called correctly.
So the solution is to include the jQuery core in the html head even if "best practices" for optimization recommends placing all script at the end of the body for faster loading times.
I do also think this is a race condition. The way I got around it is as follows:
In the HTML of the video element add the attribute preload="metadata" - to just preload the video metadata. So:
<video id="myVideo" width="640" height="480" preload="metadata" />
Next, inside the JS:
var $vid = $("#myVideo");
$vid.bind("canplaythrough", console.log("can play through full video"));
$vid.get(0).load();
This logged the message for me in Chrome - haven't tested elsewhere.
If you expect the Firefox to load the whole audio after you trigger load then it would not do this. It will fire the loadstart but will not download anything. No progress events will be fired. And it will actually do no request to that file. You can see this behavior in the Firebug.
Firefox will only start loading the file after you trigger 'play`.
Proof. See console output.
Adding:
var video = $('video');
video.trigger('load');
After adding the canplaythrough event listener fixed it for me on Firefox and Safari.
After 1.5 days of trying different approaches from here (in vanilla). The events "canplay" and "canplaythrough" with addEventListner don't work in Edge. They work fine in every other Browser. So I ended up with a check of "ready-state" with setTimout :-(. Not realy elegant, but it works for me.
Controller.prototype.backGroundControl = function () {
var vid = document.querySelector('#bgvid');
var bgImg = document.querySelector('#bgimg');
_this = this;
if (vid.readyState === 4){
bgImg.style.opacity = "0"
} else{
setTimeout(function(){
_this.backGroundControl();
},500)
}
}
I'm trying to determine when the buffering has finished from a HTML5 audio element, but so far I can't find any loadComplete or similar event. I've tried using the progress event however it doesn't fire when finished downloading - only while downloading and therefore I can't use that to check. I've also tried the standard load event but that seems not to fire at all.
What other events are there that would allow me to check if buffering is finished, or would I have to use a timer to keep checking if a.buffered.end(0) == a.duration?
Thanks,
The Audio Data API provides an event called MozAudioAvailable which does what you need. This is in Firefox 4 only, but other modern browsers may implement it in the future.