如何在没有*隔离范围的指令*中获得双向数据绑定?

mhe*_*ens 17 javascript angularjs angularjs-directive angularjs-scope

scope: { ... }在指令中使用会引入隔离范围,该范围不会从其父范围原型继承.但我总是将它用于不同的原因:使用双向数据绑定声明HTML属性的便捷方式:

scope: {
    attr1: '=',
    attr2: '?='
}
Run Code Online (Sandbox Code Playgroud)

要获得非隔离范围,必须使用scope: true,但不提供声明此类属性的机会.我现在发现自己需要一个具有非隔离范围的指令,但具有双向绑定.实现这一目标的最佳方法是什么?


示例:我的用例是这样的,在以下视图中outer-directive:

<div ng-repeat="e in element">
    <inner-directive two-way-attr="e.value"></inner-directive>
</div>
Run Code Online (Sandbox Code Playgroud)

但是和inner-directive它在同一个模块中outer-directive.它不需要用隔离范围封装.实际上,我需要将$scope继承用于其他目的,因此隔离范围不是一种选择.只是使用HTML属性来建立这种双向通信非常方便.

mhe*_*ens 14

像素位的答案帮助我解决了这个问题,但是作为我原始问题的直接答案,它看起来过于复杂.在研究之后,解决方案非常简单.

使用如下隔离范围的指令:

scope: { model: '=myModel' },
link: function(scope, element, attr) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

以下是等效的,但范围不是隔离的:

scope: true,
link: function(scope, element, attr) {
    scope.model = scope.$parent.$eval(attr.myModel);
    //...
}
Run Code Online (Sandbox Code Playgroud)

在这里查看一个工作示例:http://jsfiddle.net/mhelvens/SZ55R/1/

  • 这仅适用于模型是对象的情况. (11认同)

pix*_*its 7

在这里工作演示

同一指令中可以同时具有非隔离范围和隔离范围.您可能希望这样做,例如,如果您混合使用两个非隔离模板(意味着它们不应通过范围继承查找绑定),以及隔离模板(它们应仅在其自己的范围内查找绑定)和它们都在同一个指令中定义.

要设置隔离范围和非隔离范围,您可以执行以下操作:

  1. 在指令定义中,指定 scope=true
  2. 在链接函数中,根据scope参数编译和链接模板.执行此操作时,将针对非隔离范围评估绑定(意味着它通过原型范围继承解析绑定).

      link: function(scope, element, attr) {
    
        // this template should look for 'model' using scope inheritance
        var template2 = angular.element('<div> Prototypical Scope: {{ model }}</div>');
    
        // add the template to the DOM
        element.append(template2);
    
        // compile and link the template against the prototypical scope
        $compile(template2)(scope);
      }
    
    Run Code Online (Sandbox Code Playgroud)

    原型范围继承的优点是您不必将绑定显式导入指令的当前范围.只要它在当前作用域中定义,或者在继承链的更高位置(一直到根作用域)之前的任何作用域中定义,角度运行时将能够解析它.

  3. 在相同的链接功能中,使用定义隔离范围scope.$new(true).您可以通过将模型导入隔离范围来建立模型的双向绑定 - isolatedScope.model = scope.$eval(attr.model):

     link: function(scope, element, attr) {
    
        // this template should look for 'model' in the current isolated scope only
        var template = angular.element('<div>Isolate Scope: {{model}}</div>');
    
        // create an isolate scope
        var isolatedScope = scope.$new(true);
    
        // import the model from the parent scope into your isolated scope. This establishes the two-way binding.            
        isolatedScope.model = scope.$eval(attr.model);
    
        // add the template to the DOM
        element.append(template);
    
        // compile and link the template against the isolate scope
        $compile(template)(isolatedScope);
    
    }
    
    Run Code Online (Sandbox Code Playgroud)

    隔离范围的优点是任何存在的绑定(即在范围内)都是您明确导入的绑定.将此与非隔离范围进行对比 - 其中绑定不需要在当前范围上明确定义 - 它可以从链上方的任何范围继承.


Sam*_*Sam 6

我写了这个.你这样使用它:

twowaybinder.attach($scope, $attrs.isDeactivated, 'isDeactivated');

.factory('twowaybinder', function ($parse) {
  function twoWayBind($scope, remote, local){
    var remoteSetter = $parse(remote).assign;
    var localSetter = $parse(local).assign;

    $scope.$parent.$watch(remote, function (value) {
      localSetter($scope, value);
    });

    $scope.$watch(local, function (value) {
      remoteSetter($scope, value);
    });
  }

  return {
    attach : twoWayBind
  };
});
Run Code Online (Sandbox Code Playgroud)

它将从范围值给出真正的双向绑定.注意我不认为$ scope.$ parent是必要的,因为在继承或无范围的情况下,任何表达式都应解析当前范围.您只需要在隔离范围内调用$ parent,在这种情况下您不会使用它,您将使用隔离范围配置.