自定义ngModel标志不会立即消化

时间:2015-05-21 01:49:52

标签: angularjs

我正在尝试扩展ngModel,以便即使验证失败,我也会有$empty标志。我们用它来显示“明文”按钮。

模型覆盖正常,但我注意到标志更改不会立即应用。调用$digest会引发“进行中”错误。

myApp.directive('ngModel', function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
        var checkEmpty = function() {
            ngModel.$empty = (ngModel.$$rawModelValue === undefined || 
                ngModel.$$rawModelValue.length === 0);
        };
        checkEmpty();

        element.on('keyup', checkEmpty);
    }
  }
});

http://jsfiddle.net/sxg7nnwm/2/

3 个答案:

答案 0 :(得分:0)

您是否被迫使用keyup事件?为了避免与摘要时间有关的问题,您应该使用$viewChangeListeners来连接到ngModel的管道。

link: function(scope, element, attrs, ngModel) {
    var checkEmpty = function() {
        ngModel.$empty = (ngModel.$$rawModelValue === undefined || ngModel.$$rawModelValue.length === 0);
        console.log(ngModel.$empty);
    };
    checkEmpty();

    ngModel.$viewChangeListeners.push(checkEmpty);

    // element.on('keyup', checkEmpty);
}

小提琴:http://jsfiddle.net/mwup0s9j/1/

答案 1 :(得分:0)

嗯,我发现$timeout有效,它会在下一个周期设置我的代码:

element.on('keyup', function() {
     $timeout(checkEmpty);
});

答案 2 :(得分:0)

您只需$watch进行更改并设置变量:

scope.$watch(function(){
   return ngModel.$isEmpty(ngModel.$viewValue);
},
function(v){
   ngModel.$empty = v;
})

编辑:

当然,这是低效的,因为它注册了$watch

正如评论中正确指出的那样,$viewChangeListeners不会因无效输入而触发。绑定到元素事件也很糟糕,因为ng-model应该与DOM无关。

可行的方法是注册首先运行的$parser。这在大多数情况下都可以 - 但不能保证全部工作,因为任何其他指令都可以在我们的解析器之前(在任何时候)自由注册自己的解析器并在解析器之前使值无效有机会运行并重新设置$empty

priority: -100,
require: "ngModel",
link: function(scope, element, attrs, ngModel) {
  ngModel.$parsers.unshift(function(v) {
    ngModel.$empty = isEmpty();
    return v;
  });

  // needed for first time
  var unwatch = scope.$watch(function(){
    return isEmpty();
  }, function(v){
    ngModel.$empty = v;
    unwatch();
  });

  function isEmpty(){
    return ngModel.$isEmpty(ngModel.$viewValue);
  }
}