【问题标题】:AngularJS ng-model value is lost after custom validation directive is triggered触发自定义验证指令后,AngularJS ng-model 值丢失
【发布时间】:2014-08-14 22:22:54
【问题描述】:

我创建了一个自定义验证指令并在表单中使用它。可以触发没有问题,但是触发validation之后,发现model值就丢失了。说我有

ng-model="project.key" 

验证后,project.key 不再存在于范围内。我想我以某种方式理解 AngularJS 并做错了什么。

代码会说话。

这是我的html页面:

 <div class="container">
    ...
    <div class="form-group"
            ng-class="{'has-error': form.key.$invalid && form.key.$dirty}">
            <label for="key" class="col-sm-2 control-label">Key</label>
            <div class="col-sm-10">
                <input type="text" class="form-control text-uppercase" name="key"
                    ng-model="project.key" ng-model-options="{ debounce: 700 }"
                    placeholder="unique key used in url"
                    my-uniquekey="vcs.stream.isProjectKeyValid" required />
                <div ng-messages="form.key.$error" ng-if="form.key.$dirty"
                    class="help-block">
                    <div ng-message="required">Project key is required.</div>
                    <div ng-message="loading">Checking if key is valid...</div>
                    <div ng-message="keyTaken">Project key already in use, please
                        use another one.</div>
                </div>
            </div>
        </div>
    <div class="col-sm-offset-5 col-sm-10">
        <br> <a href="#/" class="btn">Cancel</a>
        <button ng-click="save()" ng-disabled="form.$invalid"
            class="btn btn-primary">Save</button>
        <button ng-click="destroy()" ng-show="project.$key"
            class="btn btn-danger">Delete</button>
    </div>
</form>

这是我的指令:

    .directive('myUniquekey', function($http) {
        return {
            restrict : 'A',
            require : 'ngModel',
            link : function(scope, elem, attrs, ctrl) {
                var requestTypeValue = attrs.myUniquekey;

                ctrl.$parsers.unshift(function(viewValue) {
                    // if (viewValue == undefined || viewValue == null
                    // || viewValue == "") {
                    // ctrl.$setValidity('required', false);
                    // } else {
                    // ctrl.$setValidity('required', true);
                    // }

                    setAsLoading(true);
                    setAsValid(false);

                    $http.get('/prism-cmti/2.1', {
                        params : {
                            requestType : requestTypeValue,
                            projectKey : viewValue.toUpperCase()
                        }
                    }).success(function(data) {
                        var isValid = data.isValid;
                        if (isValid) {
                            setAsLoading(false);
                            setAsValid(true);

                        } else {
                            setAsLoading(false);
                            setAsValid(false);
                        }
                    });

                    return viewValue;
                });

                function setAsLoading(bool) {
                    ctrl.$setValidity('loading', !bool);
                }

                function setAsValid(bool) {
                    ctrl.$setValidity('keyTaken', bool);
                }

            }
        };
    });

这是表单页面的控制器:

angular.module('psm3App').controller(
        'ProjectCreateCtrl',
        [ '$scope', '$http', '$routeParams', '$location',
                function($scope, $http, $routeParams, $location) {
                    $scope.save = function() {
                            $http.post('/prism-cmti/2.1', {requestType:'vcs.stream.addProject', project:$scope.project})
                            .success(function(data) {
                                $location.path("/");
                            });
                        };
                }]);

在这个错误之前,不知何故我也需要在我的自定义验证指令中处理所需的验证,如果我不这样做,所需的验证就会出错。现在想起来,可能这两个问题的根本原因是一样的:我的指令链接函数触发后模型值就没有了。

我正在使用 Angular1.3 Beta 18 BTW。

感谢任何帮助。提前致谢。

更新: 按照@ClarkPan 的回答,我立即将ctrl.$parsers.unshift() 中的代码更新为return viewValue,这使得required 验证现在运行良好,所以我不再需要下面的行了。

        // if (viewValue == undefined || viewValue == null
                    // || viewValue == "") {
                    // ctrl.$setValidity('required', false);
                    // } else {
                    // ctrl.$setValidity('required', true);
                    // }

但是{{project.key}} 仍然没有得到更新。 然后我尝试在这里注释掉这两行:

                    setAsLoading(true);
                    setAsValid(false);

模型值{{project.key}} 已更新。我知道如果任何验证失败,模型值将被清除,但我认为

                      function(data) {
                            var isValid = data.isValid;
                            if (isValid) {
                                setAsLoading(false);
                                setAsValid(true);
                            } else {
                                setAsLoading(false);
                                setAsValid(false);
                            }
                        }

in $http.get(...).success() 应该在 $digest 循环中执行,这意味着模型值应该更新。

怎么了?

【问题讨论】:

  • 我没有扫描你所有的代码,但是如果对某个字段的任何验证失败,关联的 ng-model 将被清除。通过创建&lt;input type="email" ng-model="input.something"&gt;{{ input.something }} 最容易看到这种行为。当输入不包含有效的电子邮件地址时,它将清除模型值。
  • @null,感谢您的快速回复。我知道如果验证失败,模型将不会更新。我的问题是验证全部通过后模型值没有更新,所以在我的情况下 {{project.key}} 什么都不显示。

标签: angularjs angularjs-directive angularjs-scope angular-ngmodel


【解决方案1】:

发生这种情况是因为如果模型中设置了任何无效标志,Angular 不会对范围和 $modelValue 应用任何更改。当您开始验证过程时,您将“keyTaken”有效性标志设置为 false。这告诉角度不要将值应用于模型。当 ajax 响应到达并且您将 'keyTaken' 有效性标志设置为 true 时,$modelValue 已经设置为 undefined 并且属性 'key' 消失了。尝试在 ajax 请求期间将所有有效性标志设置为 true。您必须避免在调用 ajax 之前调用 setAsLoading(true) 和 setAsValid(false) 并将所有有效性标志设置为 true。只有在ajax响应设置有效性标志之后。

【讨论】:

  • 这是真的。我最终删除“setAsLoading(true)”以确保可以将值更新到模型。
  • 您好,时隔两年多!我遇到了类似的问题,在查看docs.angularjs.org/api/ng/directive/ngModelOptions 的文档后,有一个 allowInvalid 选项,当设置为 true 时,允许无效值更新模型!祝大家玩得开心!
【解决方案2】:

注意:下面的答案仅适用于您使用 1.3 之前的 Angular 版本(在他们引入 $validators 概念之前)。


根据我对您的myUniqueKey 指令的阅读,您希望异步验证项目密钥。如果是这样,那将是你的问题。 ngModel$parser/$formatter 系统不期望异步调用。

您在$parsers 数组中使用的匿名函数没有返回值,因为$http 是一个返回方法的异步方法。您需要立即从该方法返回 viewValue

然后在你的$http调用的.success回调中,可以十个设置有效期和加载状态。我不建议您尝试更改 viewValue(除非这不是您返回 undefinedviewValue 的目的),因为它可能会触发 $parsers 的另一次运行。

所以:

ctrl.$parsers.unshift(function(viewValue){
    //...omitted for clarity

    $http.get(
        //...
    ).success(function(data){
        setAsLoading(false);
        setAsValid(data.isValid);
    });

    //... 

    return viewValue;
});

【讨论】:

  • 听起来不错。我明天试试。顺便说一句,要使 myUniqueKey 指令与 required 指令一起使用,我应该使用 push 而不是 unshift 吗?所以需要的验证会首先触发?谢谢。
  • 我认为这与定义指令时的 priority 设置有关,而不是从数组的哪一侧添加它
  • 嗨,我尝试了你的解决方案,但它仍然没有工作。返回 'viewValue' 立即使 'required' 验证工作正常,所以我可以注释掉 'if(viewValue==undefined || viewValue ==null||viewValue==""){....}'。但是“{{project.key}}”仍然没有更新,总是空的。
  • 只是为了尝试消除所有因素,您是否尝试过删除所有形式的验证(requiredmyUniqueKey 以查看是否设置了{{project.key}}
  • 未设置,因为验证失败。
【解决方案3】:

如果该值无效,默认情况下模型不会更新(如接受的答案中所述),但您可以在任何情况下使用allowInvalid in ng-model-options 来更新模型

对于问题中的输入字段:

<input type="text" class="form-control text-uppercase" name="key"
                ng-model="project.key" ng-model-options="{ debounce: 700, 
                allowInvalid: true }"
                placeholder="unique key used in url"
                my-uniquekey="vcs.stream.isProjectKeyValid" required />

【讨论】:

    猜你喜欢
    • 2013-08-17
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 2017-05-26
    • 2014-03-07
    • 1970-01-01
    • 2016-12-09
    • 2017-12-06
    相关资源
    最近更新 更多