Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Link function after transclude in Angular js

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!

like image 906
Marco Moschettini Avatar asked Mar 01 '16 18:03

Marco Moschettini


People also ask

What is Link function is used for in AngularJS?

Link: The link function deals with linking scope to the DOM. Using Code for Compile. While defining a custom directive we have the option to define a link against which either we can define a function or we have the option to assign an object which will have pre & post function.

What is transclude in AngularJS?

The ng-transclude directive facilitates AngularJS to capture everything that is put inside the directive in the markup and use it somewhere in the directive's template.

What are the differences between link and compile?

Compiling - The modified source code is compiled into binary object code. This code is not yet executable. Linking - The object code is combined with required supporting code to make an executable program. This step typically involves adding in any libraries that are required.


1 Answers

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>
like image 143
Marco Moschettini Avatar answered Oct 05 '22 02:10

Marco Moschettini