如何自动将字符串和bool变量传递给指令父作用域

时间:2015-08-28 14:28:20

标签: angularjs scope bind

我在这样的指令中绑定变量:

<path-filter-modal is-opened="filterModalIsOpened">

在指令中我使用'='绑定如下:

scope: {
   isOpened: '='
}

当我在指令中更改变量时,父作用域包含自己的值。 如何使父范围包含相同的值?

对于对象,它运行良好,但不使用字符串和布尔值。 请注意,我在我的指令中使用我的指令中定义的控制器来更改值。

2 个答案:

答案 0 :(得分:1)

因为JavaScript的设计是这样的。

在指令中定义隔离范围会创建一个新的$scope对象,该对象是一个单独的$scope对象。它与父范围的唯一关系是:$isolateScope.$parent === $parentScope它不会继承$parentScope原型。

  • 当您为$scope.isOpened分配一些基本类型(字符串/布尔值)时,实际上JavaScript引擎会在isOpened上创建变量$scope 。它与$parentScope.isOpened完全无关。

    但是现在,Angular会隐式地同步这两个变量。所以绑定原始变量仍然使two-way binding运行良好。请检查JSFiddle

  • 如果绑定到某个对象类型,则子范围和父范围将引用内存中对象的完全相同副本。更改父作用域将自动更改子作用域。因此,始终建议two-way binding绑定对象,而不是基本类型。

检查JSFiddle。我将一个原语和一个对象绑定到指令myDirective。然后在link函数中修改它们:

scope.primitiveParam = 'primitive from directive';
// $parent.primitive and primitiveParam refer to different memory; 
// Angular is responsible to sync them.
console.log(scope.$parent.primitive);
console.log(scope.primitiveParam);

scope.objectParam.name = 'object from directive';
// $parent.obj and objectParam refer to an identical object
console.log(scope.$parent.obj.name);
console.log(scope.objectParam.name);

console.log(scope.objectParam === scope.$parent.obj);

结果如下:

primitive from parent
primitive from directive
object from directive
object from directive

详细信息:Understanding Scopes(这里有许多直观的图片,清楚地说明了这些概念)

答案 1 :(得分:1)

RE:对于对象,它运行良好,但没有字符串和布尔值

我认为这是原型继承问题的常见情况。当模型来自对象时,它运行良好,但如果它来自非对象,那么可能会在子范围内创建ng模型。

要解决该问题,请使用现代方法,使用Controller as方法。或者将filterModelIsOpened放在一个对象中。第一种方法更好。

 <div ng-controller="SomeController as s">
     <path-filter-modal is-opened="s.filterModalIsOpened">
 </div>


  function SomeController() { // no need to use $scope
      this.filterModalIsOpened = false;
  }

或者如果您使用的是旧版Angular,则无法使用Controller as方法。只需在控制器中创建自己的别名:

 <div ng-controller="SomeController">
     <path-filter-modal is-opened="s.filterModalIsOpened">
 </div>


  function SomeController($scope) { 
      $scope["s"] = this;
      this.filterModalIsOpened = false;
  }

这是一篇解释原型继承的好文章:http://codetunnel.io/angularjs-controller-as-or-scope/

以下是演示为什么 总是 为模型添加前缀的原因,无论它们是对象还是原始的。

不推荐。实时代码演示:http://jsfiddle.net/hdks813z/1/

<div ng-app="App" ng-controller="Ctrl">

    <div ng-if="true">    
           <input type="checkbox" ng-model="filterModalCanBeOpened"/>
           <the-directive primitive-param="filterModalCanBeOpened"></the-directive>
    </div>    

    <hr/>
    <p>
    The value below doesn't react to changes in primitive(non-object) property 
    that is created a copy on a directive(e.g., ng-repeat, ng-if) that creates 
    child scope
    </p>    
    $scope.primitive: {{filterModalCanBeOpened}} 

</div>

angular.module('App', [])
    .directive('theDirective', function () {
    return {
        restrict: 'AE',
        scope: {
            primitiveParam: '='            
        },
        template: '<div>primitiveParam from directive: {{ primitiveParam }}; </div>',
        link: function (scope) {            
        }
    };
})
.controller('Ctrl', ['$scope', function ($scope) {
    $scope.filterModalCanBeOpened = true;
}]);

推荐:实时代码演示:http://jsfiddle.net/2rpv27kt/

<div ng-app="App" ng-controller="Ctrl as c">

    <div ng-if="true">    
           <input type="checkbox" ng-model="c.filterModalCanBeOpened"/>
           <the-directive primitive-param="c.filterModalCanBeOpened"></the-directive>
    </div>    

    <hr/>
    <p>
    The value below react to changes in primitive(non-object) property that is 
    addressed directly by its alias c, creating child scope on it would be 
    impossible. So the primitive below react to changes on 
    the c's filterModalCanBeOpened.
    </p>    
    c.primitive: {{c.filterModalCanBeOpened}} 

</div>

angular.module('App', [])
    .directive('theDirective', function () {
    return {
        restrict: 'AE',
        scope: {
            primitiveParam: '='            
        },
        template: '<div>primitiveParam from directive: {{ primitiveParam }}; </div>',
        link: function (scope) {            
        }
    };
})
.controller('Ctrl', [function () {
    this.filterModalCanBeOpened = true;
}]);