Javascript 如何在没有隔离作用域的指令*中获得双向数据绑定?

Javascript 如何在没有隔离作用域的指令*中获得双向数据绑定?,javascript,angularjs,angularjs-directive,angularjs-scope,Javascript,Angularjs,Angularjs Directive,Angularjs Scope,在指令中使用scope:{…}将引入一个隔离作用域,它通常不会从其父作用域继承。但我总是出于不同的原因使用它:通过双向数据绑定方便地声明HTML属性: scope: { attr1: '=', attr2: '?=' } 要获得非隔离作用域,必须使用scope:true,这不提供声明此类属性的机会。我现在发现自己需要一个具有非隔离作用域但具有双向绑定的指令。实现这一目标的最佳方式是什么 示例:在外部指令的视图中,我的用例是这样的: <div ng-repeat="e i

在指令中使用
scope:{…}
将引入一个隔离作用域,它通常不会从其父作用域继承。但我总是出于不同的原因使用它:通过双向数据绑定方便地声明HTML属性:

scope: {
    attr1: '=',
    attr2: '?='
}
要获得非隔离作用域,必须使用
scope:true
,这不提供声明此类属性的机会。我现在发现自己需要一个具有非隔离作用域但具有双向绑定的指令。实现这一目标的最佳方式是什么


示例:
外部指令的视图中,我的用例是这样的:

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

但是
内部指令
外部指令
位于同一模块中。它不需要用隔离作用域封装。事实上,我需要将
$scope
继承用于其他目的,因此隔离作用域不是一个选项。只是使用HTML属性建立这种双向通信非常方便。

相同的指令中可以同时具有非隔离作用域和隔离作用域。例如,如果您混合了非隔离模板(这意味着它们不应该通过作用域继承查找绑定)和隔离模板(它们应该只在自己的作用域中查找绑定),并且它们都是在同一个指令中定义的,那么您可能希望这样做

要同时设置隔离作用域和非隔离作用域,可以执行以下操作:

  • 在指令定义中,指定
    scope=true
  • 在link函数中,根据scope参数编译并链接模板。执行此操作时,将根据非隔离作用域对绑定求值(这意味着它通过原型作用域继承解析绑定)

    隔离作用域的优点是,存在的任何绑定(即在作用域中的绑定)都是显式导入的绑定。与非隔离作用域相比,绑定不需要在当前作用域上显式定义,它可以从链上更高的任何作用域继承


  • pixelbits的答案帮我解决了这个问题,但作为对我最初问题的直接回答,它似乎过于复杂了。仔细研究之后,解决方案真的很简单

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

    scope: { model: '=myModel' },
    link: function(scope, element, attr) {
        //...
    }
    
    以下内容是等效的,但范围不是孤立的:

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

    请参见此处的工作示例:

    我写了这个。您可以这样使用它:

    scope: { model: '=myModel' },
    link: function(scope, element, attr) {
        //...
    }
    
    twowaybinder.attach($scope,$attrs.isDeactivated,'isDeactivated')

    它将从范围值提供真正的双向绑定。注意,我不认为$scope.$parent是必需的,因为在继承或无作用域场景中,任何表达式都应该在当前作用域上解析。您只需要在隔离作用域中调用$parent,在这种情况下,您不需要使用它,而是使用隔离作用域配置

    您可以使用两个指令 如果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;
            };
    
        }
    });
    

    当您使用
    scope:true
    时,您可以直接访问
    scope
    那么有什么问题?scope:true将创建一个子作用域,该子作用域将典型地从其父作用域继承,因此您将能够访问指令中父作用域上定义的值。@Satpal:我知道这一点,但就我的目的而言,这是建立通信的一种相当不雅的方式。事实上,您刚才共享的链接说:“两个控制器通过$scope继承共享信息被认为是不好的形式。”我将在我的问题中添加一个用例示例。@Satpal有时需要一个类似绑定设计的组件(例如,指令通信的接口),用于与其他作用域一起使用的指令:true指令,但由于新/隔离作用域的非法组合,隔离作用域无法使用。谢谢!这看起来很有希望。今天晚些时候我会试一试。谢谢,你的回答帮助很大。但我的问题的解决方案实际上似乎要简单得多。关键是您对
    范围的使用。$eval
    。老实说,我不确定您的代码的其余部分要完成什么,但我想知道请参阅我的调整后的解决方案:$eval此处不建立真正的双重绑定,而只是复制对象引用,因此它对非对象值(标量,如字符串、数字、对象引用)不起作用。您对此进行了测试吗?我认为这是在正确的轨道上,但正如所写的那样,它将导致一个无限的摘要循环。如果查看-search中的“case:'='”,您会发现它们引入了一些额外的逻辑来防止这种情况。这个小组最好的答案,是的,我正在使用它,但到目前为止只有一个例子。我没有见过任何无限循环类型的行为。我明白你的意思,但是,如果远程值改变,那么观察者将设置本地值,这将触发本地观察者并设置远程值,依此类推。然而,这似乎没有发生。也许$parse中有什么东西阻止了它。我会仔细看一看,谢谢。这个解决方案比$eval解决方案好,因为它也适用于基本值和对象引用。注意,这不再需要了。在1.5中,我认为bindToController现在接受散列的方式与scope接受散列的方式大致相同,它将通过双向绑定将值绑定到控制器。您可以将scope设置为false设置为true。要使用非对象模型,您应该使用解析:attr=“{model}}”或attr=“{{'string'}”为什么不在此处使用$parse$解析(attr.myModel)(此.$scope)
    .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
      };
    });
    
    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;
            };
    
        }
    });