【问题标题】:AngularJS - Access to child scopeAngularJS - 访问子范围
【发布时间】:2012-11-05 20:30:22
【问题描述】:

如果我有以下控制器:

function parent($scope, service) {
    $scope.a = 'foo';

    $scope.save = function() {
        service.save({
            a:  $scope.a,
            b:  $scope.b
        });
    }
}

function child($scope) {
    $scope.b = 'bar';
}

parentchild 中读取b 的正确方法是什么?如果有必要在parent 中定义b,那么假设b 是描述与child 而不是parent 相关的内容的属性,这是否会导致语义不正确?

更新: 进一步考虑,如果不止一个孩子拥有b,则会为parent 检索b 造成冲突。我的问题仍然存在,从parent 访问b 的正确方法是什么?

【问题讨论】:

标签: angularjs


【解决方案1】:

AngularJS 中的作用域使用原型继承,当在子作用域中查找属性时,解释器将从子作用域开始查找原型链并继续到父作用域,直到找到该属性,而不是相反。

查看 Vojta 的 cmets 问题https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

简而言之:您不能从父范围访问子范围。

您的解决方案:

  1. 在父级中定义属性并从子级访问它们(阅读上面的链接)
  2. 使用服务共享状态
  3. 通过事件传递数据。 $emit 将事件向上发送到父级,直到根范围,$broadcast 向下调度事件。这可能有助于您保持语义正确。

【讨论】:

  • 另外,$emit 和 $broadcast 的不同之处在于 $emit 可以取消而 $broadcast 不能。
  • 您可能希望获得子范围的一个地方是在单元测试指令时。如果您有一个嵌入指令,则范围是用于编译元素的范围的子级。访问已编译指令的范围进行测试具有挑战性。
  • 谢谢。另一个选项可能是 localStoragengStorage 之类的依赖项。
【解决方案2】:

虽然 jm- 的答案是处理这种情况的最佳方式,但为了将来参考,可以使用范围的 $$childHead、$$childTail、$$nextSibling 和 $$prevSibling 成员访问子范围。这些没有记录,因此它们可能会在没有通知的情况下更改,但如果您真的需要遍历范围,它们就在那里。

// get $$childHead first and then iterate that scope's $$nextSiblings
for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
    // cs is child scope
}

Fiddle

【讨论】:

    【解决方案3】:

    你可以试试这个:

    $scope.child = {} //declare it in parent controller (scope)
    

    然后在子控制器(作用域)中添加:

    var parentScope = $scope.$parent;
    parentScope.child = $scope;
    

    现在父级可以访问子级的范围了。

    【讨论】:

    • 非常简洁明了。要添加到这一点,只需意识到没有绑定,因此当您像上面那样声明它时, parentScope.child 在那一刻持有子范围。要解决这个问题,您可以添加 $scope.$watch(function(){parentScope.child =$scope});以便在每次摘要之后将新范围推到父级。在父端,如果您在 html 中使用任何子范围的视觉效果,您将需要在其子变量上添加一个监视并告诉它更新范围,如下所示: $scope.$watch('child',function( ) {$scope.$evalAsync();}); .希望这可以节省一些时间!
    • @IfTrue 我相信 $watch() 不是必需的。这些是对象,它们通过引用传递。
    • @Swanidhi = 我知道你的意思,我也这么认为,但在我写评论的时候它没有用。值得我从这样做转为发射/广播。
    • 如何在 Type Script 中做到这一点?
    • 对我来说最好的答案!! javascript中通过引用处理的对象的最佳示例
    【解决方案4】:

    一种可能的解决方法是使用 init 函数将子控制器注入父控制器。

    可能的实施:

    <div ng-controller="ParentController as parentCtrl">
       ...
    
        <div ng-controller="ChildController as childCtrl" 
             ng-init="ChildCtrl.init()">
           ...
        </div>
    </div>
    

    您在ChildController 的哪个位置:

    app.controller('ChildController',
        ['$scope', '$rootScope', function ($scope, $rootScope) {
        this.init = function() {
             $scope.parentCtrl.childCtrl = $scope.childCtrl;
             $scope.childCtrl.test = 'aaaa';
        };
    
    }])
    

    所以现在在ParentController 你可以使用:

    app.controller('ParentController',
        ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {
    
        this.save = function() {
            service.save({
                a:  $scope.parentCtrl.ChildCtrl.test
            });
         };
    
    }])
    

    重要提示:
    要正常工作,您必须使用指令 ng-controller 并使用 as 重命名每个控制器,就像我在 html 中所做的那样。

    提示:
    在此过程中使用 chrome 插件ng-inspector。它将帮助您理解树。

    【讨论】:

      【解决方案5】:

      使用 $emit$broadcast,(如上面 cmets 中的 walv 所述)

      向上触发事件(从子级到父级)

      $scope.$emit('myTestEvent', 'Data to send');
      

      向下触发事件(从父级到子级)

      $scope.$broadcast('myTestEvent', {
        someProp: 'Sending you some data'
      });
      

      终于要听了

      $scope.$on('myTestEvent', function (event, data) {
        console.log(data);
      });
      

      更多详情:- https://toddmotto.com/all-about-angulars-emit-broadcast-on-publish-subscribing/

      享受:)

      【讨论】:

        【解决方案6】:

        是的,我们可以将子控制器中的变量分配给父控制器中的变量。这是一种可能的方式:

        概述:以下代码的主要目的是将子控制器的 $scope.variable 分配给父控制器的 $scope.assign

        解释:有两个控制器。在 html 中,请注意父控制器包含子控制器。这意味着父控制器将在子控制器之前执行。因此,首先将定义 setValue(),然后将控件转到子控制器。 $scope.variable 将被分配为“孩子”。然后这个子作用域将作为参数传递给父控制器的函数,其中 $scope.assign 将获取值作为“子”

        <!DOCTYPE html>
        <html>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
        <script type="text/javascript">
            var app = angular.module('myApp',[]);
        
            app.controller('child',function($scope){
                $scope.variable = "child";
                $scope.$parent.setValue($scope);
            });
        
            app.controller('parent',function($scope){
                $scope.setValue = function(childscope) {
                    $scope.assign = childscope.variable;
                }
            });
        
        </script>
        <body ng-app="myApp">
         <div ng-controller="parent">
            <p>this is parent: {{assign}}</p>
            <div ng-controller="child">
                <p>this is {{variable}}</p>
            </div>
         </div>
        </body>
        </html>
        

        【讨论】:

          猜你喜欢
          • 2014-02-22
          • 1970-01-01
          • 2013-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-19
          • 2014-10-25
          相关资源
          最近更新 更多