为什么当值更改时不触发“attr.$observe”回调

Why isn't `attr.$observe` callback triggered when value is changed

本文关键字:attr observe 回调 为什么      更新时间:2023-09-26

我编写了一个验证指令multiple-pattern,它需要几个验证正则表达式:

link: function (scope, elm, attr, ctrl) {
    if (!ctrl) return;
    let validators = [];
    attr.$observe('multiplePattern', function (patterns) {
        // doesn't get there after value change
        var parsed = scope.$eval(patterns);

但我不明白为什么当控制器validationRegexps上的变量更改时不触发$observe回调(ng-repeat regexp变量更改时触发回调(:

$scope.regexp = '^''S*$';
$scope.validationRegexps = {'nospaces': '^''S*$', 'nofirstnumber': '^[A-Za-z]'};
setTimeout(function () {
    $scope.$apply(function () {
        $scope.regexp = '[^abc]';
        $scope.validationRegexps = {'noabc': '[^abc]'};
    })
}, 5000);

用法:

<div ng-pattern="regexp" multiple-pattern="validationRegexps"></div>

$observe的工作方式与$watch相同。但这两者之间的区别在于$watchstring值或expression并评估每个摘要周期,其中$observe采用像{{validationRegexps}}这样的interpolated表达。

仅当您使用带有内值内容{{}} attribute时,attr.$observe才有效。

.HTML

<div ng-pattern="regexp" multiple-pattern="{{validationRegexps}}"></div>

我刚刚检查了源代码,似乎对ng-pattern值进行了特殊处理,可以在不指定插值的情况下正确处理$observe

var ALIASED_ATTR = {
  'ngMinlength': 'minlength',
  'ngMaxlength': 'maxlength',
  'ngMin': 'min',
  'ngMax': 'max',
  'ngPattern': 'pattern'
};

forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
  ngAttributeAliasDirectives[ngAttr] = function() {
    return {
      priority: 100,
      link: function(scope, element, attr) {
        //special case ngPattern when a literal regular expression value
        //is used as the expression (this way we don't have to watch anything).
        if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
          if (match) {
            attr.$set("ngPattern", new RegExp(match[1], match[2]));
            return;
          }
        }
        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
          // here the value is already interpolated
          attr.$set(ngAttr, value);
        });
      }
    };
  };
});

$observe的其他用例的未插值相反:

  $observe: function(key, fn) {
    var attrs = this,
        $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
        listeners = ($$observers[key] || ($$observers[key] = []));
    listeners.push(fn);
    $rootScope.$evalAsync(function() {
      if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
        // not interpolated value is passed down here
        fn(attrs[key]);
      }
    });
    return function() {
      arrayRemove(listeners, fn);
    };
  }