AngularJS - reset of $scope.value не изменяет значение в шаблоне (случайное поведение)

Взгляните на пример http://jsfiddle.net/2NJ7y/3/ (версия AngularJS 1.0.1). Существует простое приложение, которое ждет ввода счастливого номера. Если число равно 7, я reset счастливое число - null. Если я введу номер 7 несколько раз, иногда/случайно, счастливое число останется в поле ввода. Зачем? Как это поведение решается? Спасибо.

Ответ 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;
    }
})

Fiddle.

Этот другой ответ SO от @Valentyn заставил меня подумать о том, чтобы попытаться решить этот вопрос.

Ответ 3

Если вы просто положили

$scope.luckynumber = undefined;

перед предупреждением вы не устраняете условие гонки, но вы меняете его так, чтобы 7 правильно очищался, но иногда вы получаете предупреждение дважды.

Если код предупреждения заменен чем-то идемпотентным, например, изменение DOM для отображения ошибки, то эта проблема не будет иметь значения.