触发自定义验证指令后,AngularJS ng-model值将丢失

时间:2014-08-14 22:22:54

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

我创建了一个自定义验证指令并在表单中使用它。它可以毫无问题地触发,但在触发验证后,我发现模型值刚刚丢失。说我有

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的回答,我立即将我的代码更新为return viewValue ctrl.$parsers.unshift(),这使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);
                            }
                        }
$http.get(...).success()中的

应该在$ digest循环中执行,这意味着应该更新模型值。

有什么问题?

3 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:1)

注意:以下答案仅适用于您使用1.3之前的角度版本(在他们介绍$validators概念之前)。


从我对myUniqueKey指令的阅读中,您希望异步验证projectkey。如果是这种情况,那将是你的问题。 ngModel的{​​{1}}系统不期望异步调用。

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

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

所以:

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

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

    //... 

    return viewValue;
});

答案 2 :(得分:1)

如果该值无效,则默认情况下不会更新模型(如接受的答案中所述),但是在任何情况下,您都可以使用{{1 }}

对于问题中的输入字段:

allowInvalid