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

时间:2014-05-22 10:12:31

标签: javascript angularjs angularjs-directive angularjs-scope

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

scope: {
    attr1: '=',
    attr2: '?='
}

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


示例:我的用例是这样的,在outer-directive

的视图中
<div ng-repeat="e in element">
    <inner-directive two-way-attr="e.value"></inner-directive>
</div>

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

4 个答案:

答案 0 :(得分:14)

像素比特的答案帮助我解决了这个大问题,但作为我原始问题的直接答案,它似乎过于复杂。在研究之后,解决方案非常简单。

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

scope: { model: '=myModel' },
link: function(scope, element, attr) {
    //...
}

以下是等效的,但范围不是孤立的:

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

请参阅此处的工作示例:http://jsfiddle.net/mhelvens/SZ55R/1/

答案 1 :(得分:7)

Working Demo Here

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

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

  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);
      }
    

    原型范围继承的优点是您不必明确地将绑定导入您的指令&#39;目前的范围。只要它在当前作用域中定义,或者在继承链上方的任何作用域(一直到根作用域)中定义,角度运行时将能够解析它。

  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);
    
    }
    

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

答案 2 :(得分: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
  };
});

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

答案 3 :(得分:-3)

您可以使用两个指令 如果gg是一个对象,那么“=”指向一个记忆位置!

angular.module('mymodule', []).directive('a', function($parse, $modal) {
return {
    restrict : 'A',
    scope : {
        gg : "="
    },
    require : "b",
    link : function(scope, element, attrs, bCtrl) {
        scope.$watch('gg',function(gg){
            bCtrl.setset(scope.gg);
        }
    }
}
});

angular.module('mymodule').directive('b', function($parse, $modal) {

return {
    restrict : 'A',
    /*
     * scope : { showWarn : "=" },
     */
    controller : function($scope) {
        $scope.bb = {};

        this.setset = function(nn) {

            $scope.bb=nn;
        };

    }
});