¿Cómo verifico correctamente la validez del formulario dentro de un observador cuando los datos del modelo se cambian fuera del formulario en angularjs?

StackOverflow https://stackoverflow.com//questions/21034489

Pregunta

Todavía soy bastante nuevo en AngularJS y creo que tengo problemas para entender el tiempo con $scope.En un controlador, configuré un observador para algunos datos del modelo que están vinculados a varios elementos del formulario.El observador lanza una solicitud ajax cuando los datos cambian, excepto si el formulario no es válido.Estoy comprobando la validez del formulario con myForm.$valid.Sin embargo, todo esto es bastante sencillo, excepto cuando los datos del modelo se actualizan en el controlador y no en el formulario.Las validaciones se ejecutan como se esperaba, pero form.$valid todavía tiene el valor anterior, no el que debería tener con los datos actualizados.Por ejemplo, si el formulario era válido anteriormente, entonces elimino el valor del modelo vinculado a una entrada requerida, el observador se activará porque los datos del modelo han cambiado, pero cuando registro el valor de myForm.$valid su valor sigue siendo verdadero. aunque debería ser falso.

Entonces mi pregunta es la A.¿Por qué sucede esto?, pero lo más importante es B.¿Cuál es la forma correcta de manejar lo que estoy tratando de lograr?¿Tendría sentido una directiva personalizada?

Aquí hay un ejemplo simplificado.

HTML:

<div ng-controller="MyCtrl">
    <form name="myForm">
        <input type="text" name="myField" ng-model="myData" required>
        <button type="button" ng-click="myData=''">Delete</button>
    </form>

    <div>
        The watcher says the form is: <strong>{{ formStatus }}</strong>    
    </div>
</div>

Controlador:

myApp.controller('MyCtrl', ['$scope', function($scope) {
    $scope.myData = 'abc';
    $scope.formStatus = '';

    $scope.$watch('myData', function(newVal, oldVal) {
        if (newVal != oldVal) {
            console.log("my data changed");
            console.log("my form valid = ", $scope.myForm.$valid);        
            $scope.formStatus = $scope.myForm.$valid ? 'Valid' : 'Invalid';
        }
    });
}]);

Violín: http://jsfiddle.net/anpsince83/cK6cc/1/

¿Fue útil?

Solución

Una directiva personalizada es el camino correcto a seguir.En general, se recomienda, por varias razones, que los relojes se coloquen en directivas frente a controladores.En un nivel alto, una razón es que Angular recomienda que los controladores sean delgados y solo funcionen como pegamento entre la vista y los servicios.Pero estás encontrando una razón específica e interesante.

Los controladores se ejecutan antes de que se vinculen las directivas Angular.Entonces, el reloj de su controlador se agrega a la lista de vigilancia antes que el de Angular. ngModelWatch() hace por myData. ngModelWatch() es donde corre Angular $formatters (recordando que $formatters, entre otras cosas, son donde se activa la validación cuando se produce un cambio en el modelo).

Dado que las vigilancias se ejecutan en el orden en que se agregaron a la lista de vigilancia, su controlador $watch se ejecuta antes de la validación siendo hecho por $formatters.

Si en cambio pones lo mismo $watch dentro de una directiva, se agregará durante el enlace después ngModelWatch() ha sido agregado a la lista de vigilancia.De este modo la directiva $watch se ejecutará después de la validación está hecho.

Aquí está un violín actualizado donde se puede observar el orden de ejecución de $formatters y cada $watch.Y verá que la versión de la directiva funciona como se esperaba: ejecutándose después $formatters.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top