当AngularJS $ asyncValidator承诺拒绝

时间:2016-03-18 15:31:52

标签: angularjs validation

我通过指令在输入字段上运行自定义异步验证器:

angular.module("app", [])
.directive("accountDescriptionValidator", function ($q, $timeout) {
    function startValidation() {
      var startValidationDeferred = $q.defer();
      $timeout(function() { startValidationDeferred.resolve() }, 100);
      return startValidationDeferred.promise;
    }
    return {
        restrict: "A",
        require: "ngModel",
        scope: {
            parentModel: "="
        },
        link: function (scope, elm, attrs, ctrl) {
            ctrl.$asyncValidators["accountDescriptionValidator"] = function (modelValue, viewValue) {
                var accountDescriptionValidatorDefer = $q.defer();
                startValidation().then(function(accounts) {
                    if (viewValue == "aaa") {
                      accountDescriptionValidatorDefer.reject();
                    }
                    else {
                      accountDescriptionValidatorDefer.resolve();
                    }
                });
                return accountDescriptionValidatorDefer.promise;
            };
        }
    };
})

验证员的工作非常出色;但是,当验证(正确地)失败时,绑定到输入字段的模型将完全从其父对象中删除。相反,我想要的是保持最新的有效价值。这可能吗?

编辑:plnkr添加了here

EDIT2:现在问题代码与plnkr匹配

1 个答案:

答案 0 :(得分:3)

我看到了两个问题的解决方案。

  • 使用另一个变量并保留最后一个正确的值。
  • 使用allowInvalid选项。

plunker上的实例。

// Code goes here

angular.module("app", [])
  .directive("accountDescriptionValidator", function($q, $timeout) {
    function startValidation() {
      var startValidationDeferred = $q.defer();
      $timeout(function() {
        startValidationDeferred.resolve()
      }, 100);
      return startValidationDeferred.promise;
    }
    return {
      restrict: "A",
      require: "ngModel",
      scope: {
        parentModel: "=",
        lastValidValue: "="
      },
      link: function(scope, elm, attrs, ctrl) {
        ctrl.$asyncValidators["accountDescriptionValidator"] = function(modelValue, viewValue) {
          var accountDescriptionValidatorDefer = $q.defer();
          startValidation().then(function(accounts) {
            if (viewValue == "aaa") {
              console.log('invalid');
              accountDescriptionValidatorDefer.reject();
            } else {
              scope.lastValidValue = modelValue;
              accountDescriptionValidatorDefer.resolve();
            }
          });
          return accountDescriptionValidatorDefer.promise;
        };
      }
    };
  })
  .controller("ctrl", function($scope) {
    $scope.obj = {};
  });
<!DOCTYPE html>
<html>

<head>
  <script data-require="angular.js@1.5.0" data-semver="1.5.0" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>
</head>

<body ng-app="app">
  <div ng-controller="ctrl">
    <input type="text" ng-model="obj.description" account-description-validator last-valid-value="obj.lastDescription" />
    <br>Current value:{{ obj.description }}

    <br>Last valid value:{{ obj.lastDescription }}
    <br>By inserting "aaa" (without quotes) in the text field validation fails, and the model gets deleted! Instead, I'd like the model to be kept to the latest valid value. Validation has 100ms delay to simulate an async action.
    <br>
    <input type="text" ng-model="obj.description2" ng-model-options="{allowInvalid:true}" account-description-validator last-valid-value="obj.lastDescription2" />
    <br>Current value with allow invalid:{{ obj.description2 }}
  </div>
</body>

</html>