AngularJS - Access to child scope

2019-01-02 19:50发布

If I have the following controllers:

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

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

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

What's the proper way to let parent read b out of child? If it's necessary to define b in parent, wouldn't that make it semantically incorrect assuming that b is a property that describes something related to child and not parent?

Update: Thinking further about it, if more than one child had b it would create a conflict for parent on which b to retrieve. My question remains, what's the proper way to access b from parent?

标签: angularjs
6条回答
怪性笑人.
2楼-- · 2019-01-02 20:15

While jm-'s answer is the best way to handle this case, for future reference it is possible to access child scopes using a scope's $$childHead, $$childTail, $$nextSibling and $$prevSibling members. These aren't documented so they might change without notice, but they're there if you really need to traverse scopes.

// 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楼-- · 2019-01-02 20:17

Yes, we can assign variables from child controller to the variables in parent controller. This is one possible way:

Overview: The main aim of the code, below, is to assign child controller's $scope.variable to parent controller's $scope.assign

Explanation: There are two controllers. In the html, notice that the parent controller encloses the child controller. That means the parent controller will be executed before child controller. So, first setValue() will be defined and then the control will go to the child controller. $scope.variable will be assigned as "child". Then this child scope will be passed as an argument to the function of parent controller, where $scope.assign will get the value as "child"

<!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>
查看更多
看淡一切
4楼-- · 2019-01-02 20:18

Scopes in AngularJS use prototypal inheritance, when looking up a property in a child scope the interpreter will look up the prototype chain starting from the child and continue to the parents until it finds the property, not the other way around.

Check Vojta's comments on the issue https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

In a nutshell: You cannot access child scopes from a parent scope.

Your solutions:

  1. Define properties in parents and access them from children (read the link above)
  2. Use a service to share state
  3. Pass data through events. $emit sends events upwards to parents until the root scope and $broadcast dispatches events downwards. This might help you to keep things semantically correct.
查看更多
泪湿衣
5楼-- · 2019-01-02 20:25

One possible workaround is inject the child controller in the parent controller using a init function.

Possible implementation:

<div ng-controller="ParentController as parentCtrl">
   ...

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

Where in ChildController you have :

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

}])

So now in the ParentController you can use :

app.controller('ParentController',
    ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {

    this.save = function() {
        service.save({
            a:  $scope.parentCtrl.ChildCtrl.test
        });
     };

}])

Important:
To work properly you have to use the directive ng-controller and rename each controller using as like i did in the html eg.

Tips:
Use the chrome plugin ng-inspector during the process. It's going to help you to understand the tree.

查看更多
只若初见
6楼-- · 2019-01-02 20:26

You can try this:

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

then in child controller (scope) add:

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

Now the parent has access to the child's scope.

查看更多
爱死公子算了
7楼-- · 2019-01-02 20:33

I am not sure whether or not you "should" access the child scope from the parent, but it is possible. I know this because I just did it myself. Here is my scenario:

I have a function which navigates my pages by changes the string within a variable. That that variable is referenced in the main index.html file as an ng-include. So, when the string is changed, a new html file is loaded into that ng-include. Inside of one of those html files I have another ng-include. Think of this one as a smaller window within the first window. Everytime I change the content in these windows I have I also change the content of a side panel. This side panel is at the parent level. But, when I go into the smaller window within the parent, that parent level side panel has navigation links in it which change things within the small window. Since the side panel is at the parent level and the navigation for the smaller window is taken care of in its own controller at the child level, when I click on the links on the side panel it has to edit the child controller. This may be bad programming. Honestly, I don't know. I just started with angularjs a few months ago and I am still learning. But, to make it work for my scenario, I made a function in the parent scope, which is called when the child scope loads:

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

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

so, now the parent scope's variable $scope.childScope is essentially the child controller's scope. It has access to all of the variables and functions within the child scope. If this is bad programming and anyone can come up with an alternate solution to the problem with my scenario that would be great. But, this does work if necessary.

查看更多
登录 后发表回答