EDIT: Вопрос был изменен и теперь включает в себя ng-model
, так что я удалил оригинальный ответ о ngChange
требует ngModel
. Теперь, двойная компиляция (ранее упоминались как «не по теме») имеет важнейшее значение для понимания вопроса.
Важно признать, что подход, который вы принимаете, приводит к двойной компиляции других директив по этому элементу. В частности, следующие директивы представляют интерес:
ngModel
- компилируется/связаны дважды
input
- компилируется/связаны дважды
ngChange
- компилируется/связанный раз
TL; DR
ngChange
не запускает обработчик, потому что к моменту его запуска он считает, что значение не изменилось, поскольку значение было ранее изменено (и теперь оно равно значению элемента <input>
) первым экземпляром ngModel
, что в результате первой компиляции.
Longer версия:
Каждый сборник передача результатов ngModel
директивы в новом экземпляре ngModelController
. Каждый прогон компиляции директивы input
, который требует ngModel
, получает другой экземпляр ngModelController
в своей функции link
, а когда выполняется функция link
, он устанавливает слушателя, чтобы реагировать на изменения в элементе <input>
.
ngChange
, однако, зарегистрировать себя только один раз - в ngModel.$viewChangeListeners
массиве, например директивы в второйngModel
.
Так что, когда слушатель дИРЕКТИВЫ первыйinput
в уведомляет первый экземпляр ngModelController
(через ngModel.$setViewValue), that instance doesn't have the
ngChange` слушателя.
Но когда первый экземпляр ngModel
директивы устанавливает $viewValue
к значению в <input>
элементе, обработка все его $parsers
, $validators
и $viewChangeListerners
, тем $watch
обработчика второгоngModel
также устанавливает $viewValue
к тому, что из элемент <input>
.
Затем, когда работает, наконец, второгоinput
«s директива слушатель, он сравнивает $viewValue
с подстилающей <input>
элемента - теперь они равны - и пропускает весь трубопровод $parsers
/$validators
/$viewChangeListeners
.
ng-blur
не использует ngModel
, поэтому он прослушивает событие непосредственно и, таким образом, срабатывает (дважды).
Решение:
Так что, будьте осторожны двойной компиляции. Один из способов минимизировать это - и, безусловно, избегать двойной компиляции директив ngModel
/input
- это использовать terminal: true
и приоритет более высокого уровня. Вы можете сделать приоритет произвольно выше, чтобы «захватить» другие директивы, которые могут существовать на элементе:
app.directive("test", function($compile){
return {
priority: 10000,
terminal: true,
compile: function(tElem){
// Remove the attribute of the directive to avoid infinite loop
tElem.removeAttr('test');
tElem.attr("ng-change", "someFunction()");
tElemLinkFn = $compile(tElem);
return function(scope, element){
tElemLinkFn(scope, function(clone){
element.replaceWith(clone);
});
};
}
};
});
Извини дружище, я забыл упомянуть, что нг-модель есть (я только что редактировал код). Однако, спасибо за подсказку о проблеме с двойным компиляцией – brazorf
@brazorf, ну ... в этом случае двойная компиляция становится критичной - я отредактировал свой ответ –