Angular JS: получить ng-модель с ng-change

У меня есть следующий HTML

<select ng-model="country" ng-options="c.name for c in countries" ng-change="filterByCountry"></select>

Это происходит от следующего объекта со списком стран

$scope.countries = [{name:Afeganistão, country:AF}, {name:África do Sul, country:ZA}, name:Albânia, country:AL}, {name:Alemanha, country:DE}, {name:Andorra, country:AD} ...];

Когда я меняю свое выпадающее значение, я ожидал обновления моей модели ($ scope.country) внутри функции filterByCountry, но это не так. Что мне здесь не хватает?

Ответ 1

Обработчик ng-change запускается до фактического обновления ng-model. Если вы хотите, чтобы filterByCountry запускался каждый раз при изменении $scope.country (а не только при изменении выпадающего списка), вы должны использовать следующее:

$scope.$watch('country', filterByCountry);

Я всегда считаю более полезным реагировать на изменения в моих $scope, а не в DOM-событиях, когда это возможно.

Ответ 2

Просто для всех, кто придет сюда, ng-change фактически вызывается после того, как значение модели было установлено.

Почему?
Посмотрим, когда это называется. Из angular исходный код ng-change - это просто директива атрибута с этим объектом определения директивы (DDO).

{
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attr, ctrl) {
      ctrl.$viewChangeListeners.push(function() {
        scope.$eval(attr.ngChange);
      });
    }
}

Отсюда видно, что директива ng-change очень проста. Все, что ng-change='<expr>' делает, это добавить функцию в конец $viewChangeListeners, которая оценивает <expr> через $scope. $Eval.

OK... поэтому, когда вызываются ViewChangeListeners?

Хорошо, если мы посмотрим на документацию для ngModel.NgModelController:

новое значение будет применено к $modelValue, а затем выражение, указанное в атрибуте ng-model. Наконец, все зарегистрированные прослушиватели изменений в списке $viewChangeListeners называются.

Таким образом, viewChangeListener для ngChange будет вызываться после того, как значение будет применено к $modelValue. Следовательно, обратный вызов будет вызван после установки модели.

Также обратите внимание, что во всех версиях angular это поведение одинаково. Определение для ng-change не изменилось с момента v1.2.

Ответ 3

Как указал Джеймс Лоусон,

ng-change на самом деле вызывается после установки значения модели.

И если вы все еще спрашиваете

Теперь, почему я вижу противоположное поведение?

Тогда вы должны знать, что $ scope является прототипом, унаследованным от его родителя, и если ваша переменная области видимости - это просто простой тип (строка, логическое значение и т.д.), То она будет перезаписана в дочерней области значением, которое было установлено с помощью ng- модельная директива

Чтобы увидеть, где создается дочерняя область (на каком элементе DOM), вы можете открыть инструменты разработчика и найти class="ng-scope" для элемента