Why must we do this So, due to some business limitations, and much to my chagrin, I am supporting IE8 at work. I don’t even want to talk about it. BUT with that we also want to not be “bossy” in the way we show users errors in our angular code. Brings me to the point; custom angular directive to polyfill the 1.2 -> 1.3 gap in modelOptions! (also not happy to change the core of angular in this way).

Angular Code time! Get the angular module (or create)

var module = app.module('myNeatDirectives');

Create the angular directive. We use ‘input’ because we don’t want opt in function here, we don’t even want opt out now (that can be added). We also restrict to ‘E’ which is element (i.e. <input type=”text” />). We require ngModel (<input type=”text” />) but throw the ‘?’ on there for optional inclusion. Finally setting the priority to 99 so it runs after the angular binding happens.

module.directive('input', ['$sniffer', function ($sniffer) {
    return {
        restrict: 'E',
        require: '?ngModel',
        priority: 99,

Next up, the bread and butter. We check if the input is of type radio or check box, no need to do special bindings there: return; Then we use angular’ built in $sniffer to check for event bindings, in a similar fashion to how modernizr would work, unbind any bound events from the element.

link: function (scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;
            if ($sniffer.hasEvent('input')) {
                elm.unbind('input');
            }
            if ($sniffer.hasEvent('change')) {
                elm.unbind('change');
            }
            if ($sniffer.hasEvent('keydown')) {
                elm.unbind('keydown');
            }

Now we bind up our blur events and update the model.$viewValue on the blur callback.

elm.bind('blur', function () {
                if (ngModelCtrl.$viewValue === elm.val()) {
                    return;
                }
                scope.$apply(function () {
                    ngModelCtrl.$setViewValue(elm.val());
                });
            });

There are some cases (search boxes) that you may want a specific keypress to trigger events. I wanted enter to also set the value, so boom. Made it happen.

elm.bind("keydown keypress", function (event) {
                var charCode = event.which || event.keyCode;
                if (charCode === 13) { //enter key is 13
                    scope.$apply(function () {
                        ngModelCtrl.$setViewValue(elm.val());
                    });
                }
             });
//and close the rest of the curlies and squares
        }
    };
}]);