触发自定义验证指令后,AngularJS ng模型值丢失

触发自定义验证指令后,AngularJS ng模型值丢失,angularjs,angularjs-directive,angularjs-scope,angular-ngmodel,Angularjs,Angularjs Directive,Angularjs Scope,Angular Ngmodel,我创建了一个自定义验证指令,并在表单中使用它。可以毫无问题地触发它,但是在触发验证之后,我发现模型值丢失了。说我有 ng-model="project.key" 验证后,project.key不再存在于范围中。我想我理解安格拉斯错了,做了错事 代码说话 这是我的html页面: <div class="container"> ... <div class="form-group" ng-class="{'has-error': for

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

ng-model="project.key" 
验证后,
project.key
不再存在于范围中。我想我理解安格拉斯错了,做了错事

代码说话

这是我的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>
以下是表单页面的控制器:

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);
                            }
                        }
中,$http.get(…).success()应在$digest cycle中执行,这意味着应更新模型值


怎么了?

注意:以下答案仅适用于使用1.3之前的angular版本(在引入
$validators
概念之前)


根据我对
myUniqueKey
指令的阅读,您希望异步验证projectkey。如果是这样,那就是你的问题了
ngModel
$parser/$formatter
系统不需要异步调用

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

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

因此:


这是因为如果模型中设置了任何无效标志,angular不会对作用域和$modelValue应用任何更改。启动验证过程时,将“keytake”有效性标志设置为false。这说明不要将该值应用于模型。当ajax响应到达并且您将“keytake”有效性标志设置为true时,$modelValue已经设置为undefined,并且属性“key”已经消失。在ajax请求期间,尝试将所有有效性标志设置为true。在ajax调用之前,必须避免调用setAsLoading(true)和setAsValid(false),并将所有有效性标志设置为true。只有在ajax响应设置有效性标志之后。

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

对于问题中的输入字段:

<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 />


我没有扫描您的所有代码,但如果某个字段的任何验证失败,关联的ng模型将被清除。通过创建
{{input.something}}
最容易看到这种行为。当输入不包含有效的电子邮件地址时,它将清除模型值。@null,感谢您的快速回复。我知道如果验证失败,模型将不会得到更新。我的问题是,在验证全部通过后,模型值并没有更新,所以在我的例子中,{{project.key}}没有显示任何内容。听起来不错。我明天试试。顺便说一句,要使myUniqueKey指令与所需指令一起工作,我应该使用push而不是unshift吗?那么所需的验证将首先启动?谢谢。我认为这与定义指令时设置的
优先级
有关,而不是从数组的哪一侧添加指令。我尝试了您的解决方案,但仍然不起作用。返回“viewValue”会立即使“required”验证工作正常,因此我可以注释掉“if”(viewValue==undefined | | viewValue==null | | viewValue==“”){…}。但是,{{project.key}}仍然没有得到更新,始终为空。为了消除所有因素,您是否尝试过删除所有形式的验证(同时删除
必需的
myUniqueKey
,以查看
{project.key}}
是否已设置?因为验证失败,所以未设置。这是真的。我以删除“setAsLoading(true)”结束确保可以将值更新到模型中。您好,两年多之后!我遇到了类似的问题,在查看了文档之后,有一个allowInvalid选项,当设置为true时,允许无效值更新模型!祝大家玩得开心!
ctrl.$parsers.unshift(function(viewValue){
    //...omitted for clarity

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

    //... 

    return viewValue;
});
<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 />