AngularJS - 访问子范围

时间:2012-11-17 05:38:46

标签: angularjs

如果我有以下控制器:

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的正确方法是什么?如果有必要在b中定义parent,那么假设b是描述与child相关的内容而不是{{1}的属性,则不会使其在语义上不正确}}?

更新:进一步思考,如果有多个孩子parent,则会为要b parent的{​​{1}}造成冲突。我的问题仍然存在,从b访问b的正确方法是什么?

7 个答案:

答案 0 :(得分:158)

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

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

简而言之:您无法从父作用域访问子作用域。

您的解决方案:

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

答案 1 :(得分:80)

虽然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

答案 2 :(得分:48)

你可以试试这个:

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

然后在子控制器(范围)中添加:

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

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

答案 3 :(得分: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。它将帮助您理解树。

答案 4 :(得分:1)

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

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

说明:有两个控制器。在html中,请注意父控制器包含子控制器。这意味着父控制器将在子控制器之前执行。因此,首先定义setValue(),然后控件将转到子控制器。 $ scope.variable将被指定为&#34; child&#34;。然后,这个子作用域将作为参数传递给父控制器的函数,其中$ scope.assign将获得值为&#34; child&#34;

<!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>

答案 5 :(得分:0)

我不确定您是否“应该”从父级访问子范围,但这是可能的。我知道这是因为我自己就是这么做的。这是我的情景:

我有一个函数可以通过更改变量中的字符串来导航我的页面。该变量在主index.html文件中作为ng-include引用。因此,当更改字符串时,会将新的html文件加载到该ng-include中。在其中一个html文件中,我有另一个ng-include。将此视为第一个窗口中的较小窗口。每当我更改这些窗口中的内容时,我也会更改侧面板的内容。此侧面板位于父级别。但是,当我进入父级中的较小窗口时,该父级侧面板中的导航链接会改变小窗口内的内容。由于侧面板位于父级别,并且较小窗口的导航在子级别的自己的控制器中处理,当我单击侧面板上的链接时,它必须编辑子控制器。这可能是糟糕的编程。老实说,我不知道。几个月前我刚开始使用angularjs,我还在学习。但是,为了使它适用于我的场景,我在父作用域中创建了一个函数,该函数在子作用域加载时调用:

function parent($scope, service) {
    setCurrentChildController = function (childScope) {
    this.$scope.childScope = childScope;
}
}

function child($scope) {
    scope.$parent.setCurrentChildController($scope);
}

所以,现在父范围的变量$ scope.childScope本质上是子控制器的范围。它可以访问子范围内的所有变量和函数。如果这是糟糕的编程,任何人都可以提出一个替代解决方案,以解决我的方案中的问题。但是,如果有必要,这确实有效。

答案 6 :(得分:0)

使用 $ 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/

享受:)