Great Question Great Question - 9 days ago 5
AngularJS Question

Find child elements of transcluded directive but exclude its own nested directive child elements

Say I have the following code: (Plunkr: https://plnkr.co/edit/lhSmKWq3dkDScLQlXMAX)

<directive-a id="1">
<a href="">1</a>
<a href="">1</a>

<directive-b>
<a href="">1</a>
</directive-b>

<directive-a id="2">
<a href="">2</a>

<directive-a id="3">
<a href="">3</a>
</directive-a>

</directive-a>

</directive-a>


directiveA
and
directiveB
are 2 different transcluded directives. We are focusing on
directiveA
,
directiveB
is just there to represented that there can be another directive rather than
directiveA
involved.

How can each
directiveA
find and modify only its own a tag element? In other words, in this case, how can
directiveA#1
only find and modify 3 a tags,
directiveA#2
and
directiveA#3
each can only find and modify 1 a tags of its own?

See plunkr for my attempt yet no luck so far.

Answer

Please, check if this helps you.

var app = angular.module('plunker', []);

app.controller('MainCtrl', function() {
  var vm = this;
});

app.directive('directiveA', function($timeout) {
  return {
    link: function(scope, element) {
      // class name to be used as a filter
      var className = 'aClass';
      // array where suitable element ids will be collected into
      var collectedIds = [];
      // demarking boundaries - all directiveA's will have this class added to them 
      element.addClass(className);
      // initiating the collection process
      traverse(element);
      // printing the result
      console.log('scope a', scope.id, collectedIds);

      /**
       * responsible for traversing the DOM tree starting from the current
       * element collecting IDs of elements of interest.
       *
       * elements of interest in this case are:
       * "all descendants of the current node which do not have the class 'aClass'"
       */
      function traverse(element) {
        angular.forEach(element.children(), function(c) {
          // wrapping dom element
          var child = angular.element(c);
          // is the current child of a desirable/valid type
          if (isValidElement(child)) {
            var childId = child.attr('id');
            if (childId) {
              // collecting the current element's id 
              collectedIds.push(childId);
            }
            // recurssing on the current element child elements
            traverse(child);
          }
        });
      }

      /**
       * responsible for deciding if the current element
       * is of a desirable type to be traversed.
       */
      function isValidElement(element) {
        return !element.hasClass(className);
      }

    },
    restrict: 'E',
    scope: {
      id: "="
    },
    transclude: true,
    replace: true,
    template: '<div ng-transclude></div>'
  }
});

app.directive('directiveB', function() {
  return {
    restrict: 'E',
    scope: {},
    transclude: true,
    replace: true,
    template: '<div ng-transclude></div>'
  }
});
* {
  list-style-type: none;
}
<!DOCTYPE html>
<html ng-app="plunker">

<link rel="stylesheet" href="style.css" />
<script data-require="angular.js@1.5.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="app.js"></script>


<body ng-controller="MainCtrl as vm">
  <directive-a id="1">
    <a id="1" href="">1</a>
    <a id="2" href="">1</a>

    <directive-b>
      <a id="3" href="">1</a>

      <div>
        <a id="6" href="">1</a>
      </div>
    </directive-b>

    <directive-a id="2">
      <a id="4" href="">2</a>

      <directive-a id="3">
        <a id="5" href="">3</a>
      </directive-a>

    </directive-a>

  </directive-a>

  <h3>Result example in console:</h3>
  <ul>
    <li>scope a 3: [5]</li>
    <li>scope a 2: [4]</li>
    <li>scope a 1: [1,2,3,6]</li>
  </ul>
</body>

</html>