3

我在 AngularJS 中创建了一个自定义指令。该指令使用隔离作用域,它以某种方式阻止了标准 ngModel 在同一元素上的绑定。我想创建一个确认密码字段(示例中为便于阅读的文本)。

<input type="text" name="one" ng-model="fields.field_one">
<input type="text" validate-match="fields.field_one" name="two" ng-model="field_two">

当没有匹配项时,我的指令使该字段无效。

app.directive('validateMatch', function() {
  return {
    require: 'ngModel',
    scope: { matchValue: '=validateMatch' },
    link: function(scope, elm, attr, ctrl) {
      scope.$watch('matchValue', function(value) {
        ctrl.$setValidity('match', 
            ctrl.$viewValue === value
            || !ctrl.$viewValue && !value);
        });

      function validate(value) {
        ctrl.$setValidity('match', value === scope.matchValue);
        return value;
      }
      ctrl.$parsers.push(validate);
      ctrl.$formatters.push(validate);
    }
  }
});

问题是,为什么我不能通过更改模型来更改该字段的值?第一个字段工作得很好。

查看plunker了解详细信息和注释代码。

4

3 回答 3

3

正如评论中提到的,隔离范围和 ng-model 不能很好地混合。此外,我们不应该在这里使用隔离作用域,因为我们正在尝试创建一个需要与另一个指令(在本例中为 ng-model)交互的指令/组件。

由于 validateMatch 指令不创建任何新属性,因此该指令不需要创建任何新范围。 $parse可用于获取属性validate-match引用的属性的值:

app.directive('validateMatch', function($parse) {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, elm, attr, ctrl) {
      var model = $parse(attr.validateMatch);

      // watch for linked field change (field_one)
      scope.$watch(model, function(value) {
        console.log('linked change:', value, ctrl.$viewValue);
        // set valid if equal or both falsy (empty/undefined/null)
        ctrl.$setValidity('match', 
            ctrl.$viewValue === value
            || !ctrl.$viewValue && !value);
      });

      // validate on parse/format (field_two)
      function validate(value) {
        var otherFieldValue = model(scope);
        console.log('validate:', value, otherFieldValue);
        // set valid if equal
        ctrl.$setValidity('match', value === otherFieldValue);
        return value;
      }

      ctrl.$parsers.push(validate);
      ctrl.$formatters.push(validate);
    }
  };
});

笨蛋

于 2013-08-05T13:18:11.343 回答
1

按照马克的建议,我设法解决了问题。

当元素上存在隔离作用域时,ngModel 会引用它。诀窍是从内部查看父范围。您可以手动更改 ngModel(在其前面加上 $parent。),或者通过适当的编译函数在指令内自动执行此过程。

我就是这样做的:

compile: function(element, attrs, transclude) {
    // reference parent scope, because isolated
    // scopes are not looking up by default
    attrs.$set('ngModel', '$parent.'+attrs.ngModel, false);

    return function(scope, elm, attr, ctrl) {
        // link function body there
    }
}

有关完整示例,请查看此plunk

于 2013-08-04T13:16:02.873 回答
0

根据我对 AngularJS 指令的理解,您可以使用transclude参数来访问控制器的父范围。

于 2013-10-31T00:18:44.567 回答