Link function after transclude in Angular js
Asked Answered
P

1

12

I have two directives in Angular. One has to be trascluded in the other. My problem is that I can't access the DOM with simple JQuery selector after the transclude function has run. In particular I want to compile the first directive (topic) and then inject it in the other one (about-us) so I can access the DOM elements in the about-us link function. Here is the code for what I want to achieve:

<section>
    <topic active = "true" title = "Lorem ipsum" icon = "ti-layers">A) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
    <topic title = "Lorem ipsum" icon = "ti-package">B) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
    <topic title = "Lorem ipsum" icon = "ti-stats-up">C) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
    <topic title = "Lorem ipsum" icon = "ti-layout-media-center-alt">D) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
</section>

Both about-us and topic directives use transclude: true inside their configurations to compile their respective templates.

angular.module('playground', []).directive('topic', function()
{
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'path/to/topic.html',
    transclude: true,
    scope: true,
    link: function(scope, element, attributes, ctrl, transclude)
    {
        // Playing around with scope

        // Transcluding
        element.find('.tab-content p').append(transclude());
    }
  };
}).directive('section', ['$timeout', function($timeout)
{
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'path/to/about-us.html',
    transclude: true,
    link: function(scope, element, attributes, ctrl, transclude)
    {
      element.find('.tabs').append(transclude());

      // Now I want to retrieve some DOM contents after the transclude has taken place

      $timeout(function()
      {
        // Playing with DOM and JQuery but sometimes this function run prior of the child transclude function

      });
    }
  };
}]);

For the sake of completeness here is the code for the two templates:

<!-- topic.html -->
<li class="ng-class:active">
  <div class="tab-title">
      <i class="icon ng-class:icon;"></i>
      <span>{{title}}</span>
  </div>
  <div class="tab-content">
    <!-- ng-transclude directive not needed -->
    <p ng-transclude></p>
  </div>
</li>

<!-- about-us.html -->
<section class="bg-secondary pb0" id="about-us">
  <div class="container">
    <div class="row">
      <div class="col-sm-12 text-center">
        <h2 class="mb64 mb-xs-24">About us.</h2>
      </div>
      <div class="col-md-8 col-md-offset-2 col-sm-12 text-center">
        <div class="tabbed-content icon-tabs">
          <ul class="tabs"></ul>
        </div>
      </div>
    </div>
  </div>
</section>

The problem is that the $timeout function called as a work around has a completely random behaviour and sometimes it works, other times it doesn't. How can I fix this? Am I missing something about transclude, link and compile functions? Thank you for every reply!

Proud answered 1/3, 2016 at 18:46 Comment(4)
TYPO: <p ng-trasclude></p>Seena
You are right. But the issue remains the same as actually that attribute is optional with the code I've written. I'll correct it anyway in the post. Thank you for the contribution.Proud
Maybe this good article could provide some useful directions: teropa.info/blog/2015/06/09/transclusion.htmlJebel
@Jebel thank you! I've already read it and it has some interesting points, especially concerning $watcher. However I was just wondering if I could resolve my issue without using the $watcher function.Proud
P
4

I've solved my problem setting up a simple watcher on the main directive and using the transcludeFn injected by Angular in the link function.

Here's the code. Hope it could help if you have a similar problem.

angular.module('playground', []).directive('topic', function()
{
  return {
    restrict: 'AE',
    replace: true,
    templateUrl: 'path/to/topic.html',
    transclude: true,
    scope: true,
    link: function(scope, element, attributes, ctrl, transclude)
    {

      // Playing with scope...

      transclude(scope.$parent, function(clone, parent_scope)
      {
        // Transcluding
        element.find('.tab-content p').append(clone);

        // It's time to render!
        parent_scope.should_render = true;
      });
    }
  };
}).directive('Section', function()
{
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'path/to/section.html',
    transclude: true,
    scope: {},
    link: function(scope, element, attributes, ctrl, transclude)
    {
      scope.rendered = false;
      scope.should_render = false;

      transclude(scope, function(clone)
      {
        // Transcluding
        element.find('.tabs').append(clone);
      });

      // Setting up a watcher
      var remove_watcher = scope.$watch('should_render', function(should_render)
      {
        if(should_render)
        {
          if(scope.rendered)
          {
            remove_watcher();
            return;
          }

         // Now I can play with the DOM and JQuery.

          scope.rendered = true;
        }
      });
    }
  };
})

Now I can use my directive like this:

<section>
    <topic active = "true" title = "Lorem ipsum" icon = "ti-layers">A) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
    <topic title = "Lorem ipsum" icon = "ti-package">B) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
    <topic title = "Lorem ipsum" icon = "ti-stats-up">C) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
    <topic title = "Lorem ipsum" icon = "ti-layout-media-center-alt">D) Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</topic>
</section>
Proud answered 5/3, 2016 at 1:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.