2

I recently upgraded my AngularJS Framework from 1.2.0-rc.2 to the 1.2.0 release and came upon a strange issue that I haven't figured out a way around. The issue I had previous resolved was forcing an input field to fire on the on-blur event instead of the on-change event. The code for the directive I originally used was:

angular.module('app', []).directive('ngModelOnblur', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;

            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });         
            });
        }
    };
});

which is just using the suggestion found here https://groups.google.com/forum/?fromgroups#!searchin/angular/change$20blur/angular/LH0Q1A-qTVo/eyVIjJsFZGcJ

I've created two jsFiddles, one using AngularJS 1.2.0-rc.2 here, and the other using AngularJS 1.2.0 here.

The ngModleOnBlur directive should remove the 'change' binding from the <input> element and add an explicit 'blur' binding.

You'll notice that the fiddles behave differently, like the binding for elm.bind('blur', function(){...}) isn't actually being bound properly to the element, and it seems that elm.unbind('input').unbind('keydown').unbind('change') doesn't work the same in 1.2.0.

I am aware of the new ng-blur directive, but in my case I can't use that directly, but need to manually override the events bound to the element. If someone could post a working jsfiddle of how to manually override the events bound to an element, and/or explain why this has changed from 1.2.0-rc.2 to 1.2.0, that would be incredibly helpful.

Aaronias
  • 360
  • 2
  • 10

2 Answers2

2

It has to do with the order that the directives are being evaluated.

The input directive, which listens for the DOM element events, is actually being executed after your directive. Just add

priority: 1

To your directive definition. The input directive has a default priority of 0.

Here is the updated fiddle

http://jsfiddle.net/yC627/

What is strange, though, is that the documentation explicitly states that

Directives with greater numerical priority are compiled first.

but playing around with it, it seems to be the opposite. I can't tell you why that is. Hopefuly somebody else can chime in.

EDIT: I looked at the change log and it seems to be from this change

https://github.com/angular/angular.js/blob/master/CHANGELOG.md#breaking-changes-1

The documentation should really be updated to reflect this. Post-link functions are resolved in reverse priority order compared to pre-link or compile functions.

Adam
  • 1,143
  • 7
  • 7
  • Awesome find! Thank you. I had the exact same issue when I upgraded to v1.2. This solved the problem! thanks again. – Rod Hartzell Mar 20 '14 at 16:49
0

I achieved to fork & update your fiddle to work with 1.2.0 again. Is this the behaviour you had in mind? http://jsfiddle.net/P2q6B/2/

    angular.module('app', []).directive('ngModelOnblur', function() {
    return {
        restrict: 'A',
        require: '?ngModel',
        priority: 99,
        link: function(scope, elm, attr, ngModel) {
            if(!ngModel) return; // do nothing if no ng-model
            if (['radio', 'checkbox'].indexOf(attr.type) > -1) return;

            elm.unbind('input').unbind('keydown').unbind('change');

            //ui->model
            elm.on('blur', function() {
                scope.$apply(read.call(this));         
            });

            function read() {
                ngModel.$setViewValue(elm.val());
            }
        }
    };
});

If so, my way to this solution was to read angular.js sourcecode, especially search for contenteditable (around line 16k ;)

This Question seems to be related: AngularJS - Create a directive that uses ng-model

Community
  • 1
  • 1
angabriel
  • 4,979
  • 2
  • 35
  • 37
  • ok saw answer too late. actually the key part was pointed out by [adam](http://stackoverflow.com/users/2639178/adam) already. – angabriel Nov 13 '13 at 20:33