【问题标题】:Angularjs binding issues when input has a directive with scope当输入具有范围的指令时,Angularjs绑定问题
【发布时间】:2013-08-04 20:11:09
【问题描述】:

我在 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 了解详细信息和注释代码。

【问题讨论】:

标签: javascript data-binding angularjs directive


【解决方案1】:

正如评论中提到的,隔离范围和 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);
    }
  };
});

plunker

【讨论】:

  • 感觉是一种正确的方式来做到这一点,没有任何黑客。谢谢。
【解决方案2】:

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

当元素上存在独立作用域时,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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 据我了解, transclude 将指令的范围传递到它的内容和其中的所有子指令中。
    猜你喜欢
    • 2015-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 2014-04-28
    • 2014-05-26
    相关资源
    最近更新 更多