24

I would like to know how to get a list of all child scopes given a parent scope. All I can find from the properties of the scope are $$childHead, $$childTail, $$nextSibling and $$prevSibling.

The approach I'm using now is to get the childHead from the parent and then using the nextSibling to get the next child until nextSibling is null.

Is there a better approach? Given that I want to call a method [getModel] on all the children, is there again a better way of doing this?

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
ritcoder
  • 3,274
  • 10
  • 42
  • 62
  • 2
    you shouldnt be needing access to child scopes. Even if you want to make changes to child scopes when things change in the parent scope you shouldnt be directly accessing them. If you can provide a more concrete example of what you are trying to achieve, you will probably get a better answer. – ganaraj Sep 30 '12 at 08:59
  • Hi @ganaraj, what I am using directives and one directive can reference another in a parent child kinda way. The child directives are using isolated scopes and at such have their own values which are not visible from the parent. I want to access these values from the parent scope. – ritcoder Oct 01 '12 at 13:51
  • What's the final goal of that procedure? – Guillaume86 Oct 01 '12 at 15:39
  • I have a number of directives and each one is using isolated scope and has a property names 'model'. Given the parent, I want to get each child scope and then call the getModel() method on it. I have it working now. I'm just interested in other or better ways of doing the same thing. – ritcoder Oct 04 '12 at 09:12

3 Answers3

25

All Angular scope are attached to DOM element, you can start by inspecting child using the current element down to whatever child you want to reach. Once there, use below function to get the scope.

angular.element('#5th_element').scope();
Azri Jamil
  • 2,394
  • 2
  • 29
  • 37
  • Hi @wajatimur, I'm not dealing with individual elements. I already have access to the first child of the rootScope and I can get the child scopes by continually fetching the next sibling. It works but does not seem very 'angular' to be. – ritcoder Nov 22 '12 at 00:12
  • Yup, that was on my thought when first time adapting angular js on my project. But im sure there must be a good reason on this matter. – Azri Jamil Nov 24 '12 at 09:22
  • It is interesting but I redesigned the directive yesterday and there was no need to get access to the individual scopes as the data object was being populated fine and I am also using events. – ritcoder Nov 26 '12 at 15:53
  • Ok, good to hear that. It's useful please share on [Angular Example](https://github.com/angular/angular.js/wiki/JsFiddle-Examples) using JSFiddle for other buddies. – Azri Jamil Nov 27 '12 at 06:48
  • 1
    It won't work using [debug data disabled](https://docs.angularjs.org/guide/production) from angularJS 1.3. – Toilal Nov 24 '14 at 13:22
16

The child directives are using isolated scopes and at such have their own values which are not visible from the parent. I want to access these values from the parent scope.

The 'Angular way' to deal with the issue of "parent scopes needing access to child scopes" is to move the model up into the parent, and have the child scopes reference the parent properties/data (rather than the child scopes having their own local properties/copies). E.g., this is how we deal with ng-repeat if each iteration contains, say, an input form element (i.e., each iteration needs two-way databinding): Difficulty with ng-model, ng-repeat, and inputs

With directives, first define an array of objects in the parent scope, then have each isolated child scope access that parent scope array (or individual object) using the '=' notation (i.e., two-way databinding notation). Because an object is being shared, the isolated scopes will reference the parent objects (they will not get a local copy). Now, any changes you make to the child scopes properties are actually changing the parent scope properties.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Can you explain what exactly you mean by the `=` notation? – nh2 Apr 29 '13 at 10:31
  • 2
    @nh2, e.g., suppose your HTML has `
    `. If your directive specifies `scope: { myObj: '=' }`, then both the parent scope and the directive's isolate scope have access to object `someObj`. In the directive, you would refer to it in the linking function as `scope.myObj`.
    – Mark Rajcok Apr 29 '13 at 14:06
  • 1
    The problem with using isolate scope on a directive, and referencing an object via "=" is that you will only be able to register your own scopes, other scopes created by angular such as the ng-repeat scope will be omited. Another angular way would be not to use scope on the directives (defaults to scope true which inherits from parent scope) and access an **object** created at the parent scope of which you want to know it's child scopes and proceed with the same logic – HeberLZ Sep 02 '14 at 14:28
  • @HeberLZ This is what I ended up doing. I built a widget-factory-of-sorts and I faced the callenge of communicating the whole widgety thing. I ended up defaulting to **always** `scope: true` in directives, and then used pseudo-global objects in the parents to make stuff available to widgets (from objects to functions). – tfrascaroli Sep 04 '15 at 07:28
5

In AngularJS 1.3.2, a countChildScopes method was added to the ngMock module:

/**
* @ngdoc method
* @name $rootScope.Scope#$countChildScopes
* @module ngMock
* @description
* Counts all the direct and indirect child scopes of the current scope.
*
* The current scope is excluded from the count. The count includes all isolate child scopes.
*
* @returns {number} Total number of child scopes.
*/
function countChildScopes(scope) 
  {
  // jshint validthis: true
  var count = 0; // exclude the current scope
  var root = scope || angular.element(document).injector().get('$rootScope');
  var pendingChildHeads = [root.$$childHead];
  var currentScope;

  while (pendingChildHeads.length) 
    {
    currentScope = pendingChildHeads.shift();

    while (currentScope) 
      {
      count += 1;
      pendingChildHeads.push(currentScope.$$childHead);
      currentScope = currentScope.$$nextSibling;
      }
    }

  return count;
  }

Use an object as a return value to get the IDs:

function enumerateChildScopes(scope) 
  {
  // jshint validthis: true
  var enum = {}; // exclude the current scope
  var root = scope || angular.element(document).injector().get('$rootScope');
  var pendingChildHeads = [root.$$childHead];
  var currentScope;

  while (pendingChildHeads.length) 
    {
    currentScope = pendingChildHeads.shift();

    while (currentScope) 
      {
      enum["scope"+pendingChildHeads.length] = currentScope.$id;
      pendingChildHeads.push(currentScope.$$childHead);
      currentScope = currentScope.$$nextSibling;
      }
    }

  return enum;
  }

References

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265