AngularJS-访问子范围


110

如果我有以下控制器:

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

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

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

parentb出的正确方法是child什么?如果有必要定义bparent,也不会使它语义上不正确假设b是描述相关的东西的属性child,而不是parent

更新:对此进行进一步的思考,如果有一个以上的孩子b,将会parentb检索上产生冲突。我的问题是,什么是访问的正确方法是bparent


1
另外,请确保您阅读以下内容:stackoverflow.com/questions/14049480/…非常详尽的angularJS范围和继承概述。
马丁·

Answers:


162

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

查看Vojta对这个问题的评论https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

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

您的解决方案:

  1. 在父母中定义属性并从孩子那里访问它们(阅读上面的链接)
  2. 使用服务共享状态
  3. 通过事件传递数据。$emit向父级向上发送事件,直到根作用域$broadcast向下发送事件为止。这可以帮助您保持语义上正确。

8
加上$ emit和$ broadcast之间的区别是$ emit可以取消,而$ broadcast不要。
Azri Jamil

您可能希望获得子作用域的一个地方是单元测试指令。如果您有一个已包含的伪指令,则范围是用于编译元素的范围的子级。要访问已编译指令的范围进行测试是具有挑战性的。
pmc

谢谢。另一个选择可能是localStorage带有的依赖项ngStorage
阿卡什

81

尽管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
}

小提琴


49

您可以尝试以下方法:

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

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

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

现在,父母可以访问孩子的范围了。


1
非常干净和直接。补充一点就是,要意识到没有绑定,因此当您像上面那样声明它时,parentScope.child此时将持有childs范围。为了解决这个问题,您可以添加$ scope。$ watch(function(){parentScope.child = $ scope}); 这样,在每次摘要之后,它将新作用域推到父级。在父级上,如果您在html中使用任何子范围进行可视化,则需要在其子变量上添加一个监视,并告诉它更新范围,如下所示:$ scope。$ watch('child',function( ){$ scope。$ evalAsync();}); 。希望这可以节省一些时间!
IfTrue 2015年

2
@IfTrue我认为不需要$ watch()。这些是对象,它们通过引用传递。
斯瓦尼迪2015年

2
@Swanidhi =我知道您的意思,我也这么认为,但是当我在写评论时尝试时,它没有用。值得的是,我从执行此操作切换为发出/广播。
IfTrue 2015年

1
如何在Type Script中执行此操作?
ATHER

对我来说最好的答案!javascript中作为参考处理的对象的最佳示例
Vikas Gautam

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-controlleras像我在html eg中那样重命名每个控制器。

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


3

使用$ emit$ broadcast,(如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/

请享用 :)


1

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

概述:以下代码的主要目的是将子控制器的$ 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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.