8

I'll start with the question. When a specific browser has a buggy implementation of a feature and your javascript needs to know whether the current browser has that buggy implementation or not so it can use an alternate strategy, how do you figure out if the implementation is buggy without doing browser type sniffing (which is generally considered bad)?

Here's the whole situation.

I was working on some code that wants to use the "input" event for getting notifications of user changes to an <input type="text"> field (works much more live than the "change" event), but when that event isn't supported, it uses a much more complicated scheme involving a bunch of other events.

Since the "input" event is only supported in some browsers, I went in search of a way to do feature detection for the event (rather than browser user agent sniffing) since feature detection is generally a more robust way of doing things. As such, I came across this great article for doing exactly that and this code seems to work:

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;
  })();

Then, I ran into problems with IE (surprise, surprise). While IE purports to support the "input" event and it passes the feature test above and it works most of the time, IE's support is buggy as hell. It doesn't even trigger the event when the user hits the backspace key (among other missing behaviors). As such, I can't rely on it in IE. So, I had built this nice clean code that did a feature test for the "input" event and uses it's very clean implementation when present and when not present used this much uglier work-around involving monitoring eight other events. Now, it's busted in IE because the feature test for the "input" event passes so the code attempts to use it, but it's buggy as hell so it doesn't work.

Since these IE bugs show up on user actions, I can't think of any way to devise a javascript feature test to identify the buggy behavior. As such, my only current path is to resort to browser sniffing and refuse to rely on the "input" tag if the browser is IE.

Are there any options here for identifying the buggy behavior in the "input" event besides browser sniffing? If one had to do browser sniffing, is there a way to identify IE by behavior rather than a user agent string that can be freely spoofed and isn't guaranteed to be accurate?

Sam Hanley
  • 4,707
  • 7
  • 35
  • 63
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • 1
    One good thing (maybe the only?) with IE is [conditional comments](http://msdn.microsoft.com/en-us/library/ms537512.aspx) where you can put IE-specific code to solve your problem. – some Aug 29 '12 at 07:03
  • Here's is a good [oninput event](http://help.dottoro.com/ljhxklln.php) article. Unfortunately there doesn't seem to be a good alternative in IE, so even if you can detect it, there's not a lot you can do. Web developers have been doing without oninput for a long time, so if you update your question to state what you are trying to do, alternatives can be suggested. – RobG Aug 29 '12 at 07:06
  • 1
    @RobG - I'm trying to implement some dynamic behavior that responds no matter how an input field is changed. Web developers have been doing without a reliable `input` event by just accepting an imperfect implementation that doesn't trigger on drag/drop or when the field is changed via the context menu and so on. I'm trying to do better than has been done before. – jfriend00 Aug 29 '12 at 07:28
  • Can you not just use `keydown`? Am I missing something? – Eric Aug 29 '12 at 20:55
  • 2
    @Eric - `keydown` misses a bunch of ways the user can change an input field such as drag/drop, right-click cut/copy/paste. In fact to cover all forms of user change, I end up monitoring 6 other events besides `keydown`. – jfriend00 Aug 29 '12 at 21:05
  • Have you considered bypassing the test altogether and applying your solution as a universal override or extension of the implementation, thereby having full control of the critical resource? Also, I'm not sure that browser detection is actually a bad thing. MS has made it manditory for proper end-user experiences, and if it were me I'd test for IE and where found force the functionality through the target's prototype. – patrickgamer Aug 31 '12 at 09:43

2 Answers2

1

jamie-pate suggest something like this:

   var broken = false,
        ta = angular.element('<textarea>').on('input', function(evt) {
            broken = true;
        });
    ta.attr('placeholder', 'IESUCKS');

So you can check for "supports input event and is not 'broken'" in your code.

See https://github.com/angular/angular.js/issues/2614?source=c

0

If you are interested in a cross-browser "input change" event, here is my implementation:

function onInputChange(domInput, callback) {
    if (domInput.addEventListener) {
        domInput.addEventListener('input', callback, false); // Firefox, etc.
    } else if (domInput.attachEvent) {
        domInput.attachEvent('onpropertychange', callback); // IE
    }
}


Usage example:

var leInput = document.getElementById('myInput');
var leCallback = function () {
    // awesome stuff here
};

onInputChange(leInput, leCallback);


Works in all browsers, supports keyboard input and copy/paste.

However there is the exception of that cursed IE9, which didn't exist at the time I wrote the above code. Would Microsoft ever consider fixing their bug? :\

Gras Double
  • 15,901
  • 8
  • 56
  • 54
  • 1
    Thx, not exactly what I'm looking for and has the specific problem I asked this question about in IE9 which supports both `addEventListener()` and the `input` event, but the `input` event behavior is buggy as hell. – jfriend00 Aug 31 '12 at 15:36