Взгляните на пример http://jsfiddle.net/2NJ7y/3/ (версия AngularJS 1.0.1). Существует простое приложение, которое ждет ввода счастливого номера. Если число равно 7, я reset счастливое число - null. Если я введу номер 7 несколько раз, иногда/случайно, счастливое число останется в поле ввода. Зачем? Как это поведение решается? Спасибо.
AngularJS - reset of $scope.value не изменяет значение в шаблоне (случайное поведение)
Ответ 1
Я сделал некоторую отладку.
Во-первых, для меня счастливое число остается в поле ввода не случайно.
enter 3 (model==3, input==3)
= > enter 7 (alert, model==null, input="")
= > enter 3 (model==3, input==3)
= > remove 3 (model=="", input=="")
= > enter 7 (alert, model==null, input="")
= > enter 7 (alert, model==null, input="7")
7 остается в поле ввода только в том случае, если предыдущее значение модели было нулевым.
Что происходит: когда вы вводите входное событие 7, которое обрабатывается функция прослушивателя . Функция прослушивателя вызывает $setViewValue. $setViewValue устанавливает $viewValue, $modelValue, значение модели и вызывает $viewChangeListeners (ngChangeDirective просто добавляет обработчик в $viewChangeListeners). Отобразится предупреждение, значение luckynumber равно null. В конце концов, если luckynumber отличается от предыдущего значения предыдущей грязной проверкой $watch handler и $render.
В моих примерах $render вызывается, если предыдущее значение модели было "3" или "". Если предыдущее значение модели было равно null, рендер не вызывается.
Почему $timeout с задержкой 0 работает: когда вы вызываете $timeout с функцией задержки 0 с изменением количества удачных вызовов на null, переносится в конце очереди событий (все javascript в браузере выполняется в одном потоке). $viewChangeListener не изменяет значение модели от 7 до нуля. $digest заканчивается. Затем вызывается $timeout handler. Значение модели равно null. $watch handler и $render. $render присваивает входному значению значение "".
Ответ 2
Наконец, решение. Используйте $watch вместо ng-change:
$scope.$watch('luckynumber', function() {
if ($scope.luckynumber == 7) {
alert('The lucky number mustn\'t be equal 7.');
$scope.luckynumber = null;
}
})
Этот другой ответ SO от @Valentyn заставил меня подумать о том, чтобы попытаться решить этот вопрос.
Ответ 3
Если вы просто положили
$scope.luckynumber = undefined;
перед предупреждением вы не устраняете условие гонки, но вы меняете его так, чтобы 7 правильно очищался, но иногда вы получаете предупреждение дважды.
Если код предупреждения заменен чем-то идемпотентным, например, изменение DOM для отображения ошибки, то эта проблема не будет иметь значения.