Detecting support for a given JavaScript event?
Asked Answered
C

4

30

I'm interested in using the JavaScript hashchange event to monitor changes in the URL's fragment identifier. I'm aware of Really Simple History and the jQuery plugins for this. However, I've reached the conclusion that in my particular project it's not really worth the added overhead of another JS file.

What I would like to do instead is take the "progressive enhancement" route. That is, I want to test whether the hashchange event is supported by the visitor's browser, and write my code to use it if it's available, as an enhancement rather than a core feature. IE 8, Firefox 3.6, and Chrome 4.1.249 support it, and that accounts for about 20% of my site's traffic.

So, uh ... is there some way to test whether a browser supports a particular event?

Cyclothymia answered 20/5, 2010 at 20:4 Comment(2)
FYI, the phrase you're looking for is not "progressive enhancement" but rather "graceful degradation". Progressive enhancement is when you make your website accessible to all users but add features to a more specific group of users (JavaScript-enabled, HTML5-supporting, etc). Graceful degradation is when you depend on certain functionality, but have a backup method if it is not supported by the client. Not that it really matters. :)Quintero
Hmm. I would argue that "graceful degradation" means that a web site continues to function even when functionality it ordinarily relies on is unavailable. By contrast, "progressive enhancement" is when a site enables extra features that it does not rely on, only when the user agent supports them. I'm planning on writing this particular code in such a way that it does not modify the location.hash property at all unless the hashchange event is available. So that's a progressive enhancement. And yeah, not that it really matters -- they're just two sides of one coin.Cyclothymia
T
35

Well, the best approach is not going through browser sniffing, Juriy Zaytsev (@kangax) made a really useful method for detecting event support:

var isEventSupported = (function(){
  var TAGNAMES = {
    'select':'input','change':'input',
    'submit':'form','reset':'form',
    'error':'img','load':'img','abort':'img'
  }
  function isEventSupported(eventName) {
    var el = document.createElement(TAGNAMES[eventName] || 'div');
    eventName = 'on' + eventName;
    var isSupported = (eventName in el);
    if (!isSupported) {
      el.setAttribute(eventName, 'return;');
      isSupported = typeof el[eventName] == 'function';
    }
    el = null;
    return isSupported;
  }
  return isEventSupported;
})();

Usage:

if (isEventSupported('hashchange')) {
  //...
}

This technique is now used in some libraries like jQuery.

Read more here:

Tonl answered 20/5, 2010 at 20:10 Comment(9)
That's a very interesting method... I particularly like the extra check of seeing if 'return;' gets converted to a function automatically.Sacksen
This looks like the most robust method. Thanks for posting it!Cyclothymia
+1 for mentioning jQuery, jQuery is really the best, it solves all kinds of browser problems and is good, as wellCristiano
@BlueRaja, I'm only mentioning jQuery as a reference, that a serious library is relying on this technique.Saiff
Credit where it's due: Thank you @CMS for this trick! I used it to answer #13086900Drogheda
This method does not work for the 'onhashchange' event. The function has a flaw in that it will miss any events that are attached to the window object only. Also, it does not make sense to add "'hashchange':'window'" to the list of TAGNAMES since a new window element cannot be created, I believe. With "isEventSupported('hashchange')" the createElement() function will return a div which won't have the onhashchange event as a property and so the test fails even though window.onhashchange might be true.Murmurous
@CMS - You should add prefix checking as wellGaiety
it returns false for readystatechange on Chrome even though it worksDominiquedominium
"Detecting event support without browser sniffing" Link now broken (404)Garrard
S
27

The Mozilla documentation suggested the following:

if ("onhashchange" in window) {
    alert("The browser supports the hashchange event!");
}

This works in IE8 and the Chrome 5 beta too (I didn't test Chrome 4.1), and correctly fails in Opera and Safari.

Edit: the Mozilla page I linked to no longer contains any suggestions. I can't find any other Mozilla docs containing suggestions for event detection either.

Sully answered 20/5, 2010 at 20:17 Comment(3)
Very elegant. I may use a version of this modified with some ideas from the other answer that got posted. Thanks.Cyclothymia
@Keavon it works for me. But you have to use "onclick". But also see the accepted answer and the blog it links to.Sully
@Sully Ah, I forgot the on prefix, thanks. I'll delete my comment.Uhland
O
2

Here is a modification of the answer provided by CMS, which doesn't contain a function in another, which I think would work:

function event_exists(eventName){
    if(typeof(eventName)!='string' || eventName.length==0)return false;
    var TAGNAMES = {
        'select':'input','change':'input',
        'submit':'form','reset':'form',
        'error':'img','load':'img','abort':'img'
    }
    var el = document.createElement(TAGNAMES[eventName] || 'div');
    eventName = 'on' + eventName;
    var isSupported = (eventName in el);
    if (!isSupported) {
        el.setAttribute(eventName,'return;');
        isSupported = (typeof(el[eventName])=='function');
    }
    el = null;
    return isSupported;
}
Oneself answered 30/9, 2014 at 15:34 Comment(1)
Why do you need to create a new element? What's wrong with just doing a simple typeof check on the event class? (see my answer)Intratelluric
I
0

I think the simplest solution is to just do a typeof check on the event class.

For example: typeof(InputEvent) returns "function" in Chrome and "undefined" in Internet Explorer.

Intratelluric answered 8/11, 2021 at 22:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.