2015-07-16 3 views
1

Это моя директива:AngularJS нг-изменения не стреляющие при компиляции внутри директивы

directive('test', ['$compile', function ($compile) { 
     return { 
      restrict: 'A', 
      link: function(scope, element, attrs) { 
       element.attr('ng-change', "someFunction()"); // <--- Doesnt Work 
       element.attr('ng-blur', "someFunction()"); // <--- Works 
       element.removeAttr('test'); 
       $compile(element)(scope); 
      } 
     }; 
    }]) 

Marup это

<input ng-model="foo" test /> 

Теперь blur обработчик быть вызван, в то время как change обработчик нет. Зачем?

ответ

2

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); 
     }); 
     }; 
    } 
    }; 
}); 
+0

Извини дружище, я забыл упомянуть, что нг-модель есть (я только что редактировал код). Однако, спасибо за подсказку о проблеме с двойным компиляцией – brazorf

+0

@brazorf, ну ... в этом случае двойная компиляция становится критичной - я отредактировал свой ответ –

Смежные вопросы