如何将字符串和布尔变量自动传递给指令父范围

How to pass string and bool variables automatically to directive parent scope

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

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

并且在指令中我使用“=”绑定,如下所示:

scope: {
   isOpened: '='
}

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

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

因为JavaScript就是这么设计的

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

  • 当您将一些原始类型 (string/boolean) 分配给 $scope.isOpened 时,实际上 JavaScript 引擎将创建一个 new $scope 上的变量 isOpened。和$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(这里有很多直观的图片清楚地说明了概念)

回复:对于对象它工作得很好但不适用于字符串和布尔值

我认为这是原型继承问题的常见情况。当模型来自对象时效果很好,但如果它来自非对象,则 ng-model 有可能是在子范围内创建的。

要解决该问题,请使用现代方法,使用 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;
}]);