Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular $parent and $parent.$parent are the same controller when using ng-repeat

I would like to understand why when using a ng-repeat with a certain controller on the item of the repeat, the parent of that item and the grandfather of that item are the same controller. I was expecting the grandfather to be the parent of the parent controller, not the same controller.

Here the code to clarify this

HTML

<div ng-controller="MainController">
  {{name}}
  <div ng-controller="SecondController">
  {{name}}
    <ul>
      <li ng-repeat="item in list" ng-controller="ItemController">
         {{item.name}} {{$parent.name}} {{myDad}} {{myGrandpa}}
      </li>
    </ul>
    <div ng-controller="ThirdController">
         {{name}} {{$parent.name}} {{myDad}} {{myGrandpa}}
    </div>
  </div>
</div>

JS

angular.module('app', []);


angular.module('app')
  .controller('MainController', function($scope) {
  $scope.name = "MainController";
 })
.controller('SecondController', function($scope) {
  $scope.name = "SecondController";
  $scope.list = [
   {'name': 'aaa'}
  ];
})
.controller('ItemController', function($scope) {
  $scope.name = "ItemController";
  $scope.myDad = $scope.$parent.name;
  $scope.myGrandpa = $scope.$parent.$parent.name;
})
.controller('ThirdController', function($scope) {
  $scope.name = "ThirdController";
  $scope.myDad = $scope.$parent.name;
  $scope.myGrandpa = $scope.$parent.$parent.name;
});

Here a CodePen

like image 607
stilllife Avatar asked Sep 30 '22 03:09

stilllife


1 Answers

In Angular, $scope inherits and not controllers.

Each controller created by ng-controller creates a new $scope (childScope) that inherits from the $scope it exists in. I think you might want to read this answer to understand how exactly $scope inherits (prototypical inheritance).

Please not that you don't have to use "$parent" in order to get the name of the parent $scope, for example if you would remove $scope.name from ItemController and would try to bind {{name}} your template will be compiled and linked and the value of {{name}} would be "SecondController" in your example.

Regarding the $broadcast, You should try to avoid using $rootScope.$broadcast as it will dispatch an event down to all of the $scopes in your application. I'm not sure what your use case is, but if you want to execute a method that is defined in your "MainController" for instance, you can just call it for example

angular.module('app', []);


angular.module('app')
  .controller('MainController', function($scope) {
  $scope.name = "MainController";
  $scope.doSomething = function() {
    console.log("Do it");
  }
 })
.controller('SecondController', function($scope) {
  $scope.name = "SecondController";
  $scope.list = [
   {'name': 'aaa'}
  ];
})
.controller('ItemController', function($scope) {
  $scope.name = "ItemController";
  $scope.myDad = $scope.$parent.name;
  $scope.myGrandpa = $scope.$parent.$parent.name;
  $scope.clickItem = function() {
     console.log("Item clicked");
     $scope.doSomething(); // The method from "MainController" will be executed unless ItemController is isolated 
  }
})
.controller('ThirdController', function($scope) {
  $scope.name = "ThirdController";
  $scope.myDad = $scope.$parent.name;
  $scope.myGrandpa = $scope.$parent.$parent.name;
});
like image 185
Asaf David Avatar answered Oct 06 '22 18:10

Asaf David