AngularJS – o reset de $ scope.value não altera o valor no modelo (comportamento random)

Dê uma olhada no exemplo em http://jsfiddle.net/2NJ7y/3/ (versão do AngularJS 1.0.1). Há aplicativo simples, que está à espera de entrar no número da sorte. Se o número for igual a 7, redefino o número da sorte para nulo. Se eu digitar o número 7 várias vezes, em algum momento / aleatoriamente, o número da sorte permanecerá no campo de input. Por quê? Como esse comportamento resolve? Obrigado.

Eu fiz alguns debugging.

Em primeiro lugar, para mim, o número da sorte permanece no campo de input não aleatoriamente.

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 permanecer no campo de input somente se o valor do modelo anterior fosse nulo.

O que acontece : quando você digita 7 events de input acionados que são manipulados pela function listener da diretiva de input . Função de escuta chama $ setViewValue . $ setViewValue define $ viewValue, $ modelValue, valor do modelo e chama $ viewChangeListeners (ngChangeDirective simplesmente adiciona o manipulador a $ viewChangeListeners). Alerta é exibido, luckynumber é definido como null. Depois de tudo isso, se luckynumber difere do valor anterior na verificação anterior do verificador $ watch e $ render são chamados.

Nos meus exemplos, $ render é chamado se o valor do modelo anterior for “3” ou “”. Se o valor do modelo anterior era null, $ render não é chamado.

Por que $ timeout with 0 delay funciona : quando você chama $ timeout com function 0 delay, a mudança de luckynumber para null é adiada no final da fila de events (todos os javascript em um navegador são executados em um único thread). $ viewChangeListener não altera o valor do modelo de 7 para nulo. $ digest termina. Então o manipulador $ timeout é chamado. O valor do modelo é definido como nulo. $ watch manipulador e $ render são chamados. $ render define o valor de input para “”.

Finalmente, uma solução. Use $ watch em vez de ng-change:

 $scope.$watch('luckynumber', function() { if ($scope.luckynumber == 7) { alert('The lucky number mustn\'t be equal 7.'); $scope.luckynumber = null; } }) 

Violino .

Essa outra resposta do SO feita por @Valentyn me fez pensar em tentar essa solução para essa questão.

Se você simplesmente colocar

 $scope.luckynumber = undefined; 

Antes do alerta, você não elimina a condição de corrida, mas você o altera para que 7 seja limpo corretamente, mas às vezes você recebe o alerta duas vezes.

Se o código de alerta for substituído por algo idempotente, como alterar o DOM para exibir um erro, esse problema não será importante.