2

Im using angular 1.x and I have created a custom directive called slider as following code.

I'm trying to transclude the content of slider directive in order to modify it inside the transclude function. But the problem is clone is not giving a collection of .slide elements. Instead it gives a comment which relates to ng-repeat. I cannot get the compiled output of ng-repeat which should be a collection of .slide divs. I want to know how to access the result of ng-repeat inside transclude function so that I can successfully call scope.showCurrent. Now what happens is, $('.slide') call inside scope.showCurrent() doesnt catch any .slide divs because at the time of call there are no .slide elements. But if ng-repeat provided its compiled html inside transclude function, $('.slide') will catch divs.

app.directive('slider', function ($compile) {
     return {
          restrict: 'EA',
          priority: 1200,
          scope: true,
          controller: function ($scope) {
               $scope.slider = { currentIndex: 0 };
          },
          transclude:'element',
          link: function (scope, el, attrs, ctrl, transclude) {

               scope.showCurrent = function (currentIndex) {
                    console.log('x')
                    $('.slide').hide();
                    $('.slide').eq(currentIndex).show();
               }

               scope.$watch('slider.currentIndex', function (val) {
                    console.log('tst');
                    scope.showCurrent(val);
               });

               transclude(scope, function (clone) {
                    el.after(clone);
                    scope.showCurrent(scope.slider.currentIndex);
               })
          },
     }
});

Following is the html usage of this directive.

<slider>
  <div ng-repeat="slide in slides" class="slide">
     <div>Image {{img}}</div>
     <img ng-src="img"/>
   </div>
</slider>

Here is my plunk https://plnkr.co/edit/m7YJBNuDjeLPaKkUYK5S?p=preview

RIYAJ KHAN
  • 15,032
  • 5
  • 31
  • 53
XPD
  • 1,121
  • 1
  • 13
  • 26
  • why do you want to use transclusion here? your directive doesn't create isolate scope, and transclusion is usually used to bind inner elements to outer scope – Max Koretskyi Oct 09 '16 at 18:15
  • I explained in [my answer](http://stackoverflow.com/a/39947320/2545680) why you don't get `slides`. If you clearly explain what is your original intent, I may be able to provide a solution – Max Koretskyi Oct 09 '16 at 19:11
  • Thanks Maximus and you're right. What I wanted was to modify the content of the clone inside transclude function. The problem was I think its because ngRepeat itself another transcluded directive which is not rendered while in link function of slider directive I created. The workaround I found was to add another directive on ngRepeat which signals the rendering complete event which emitted up with scope.$emit and catch that in the slider directive as indicated by http://stackoverflow.com/questions/15207788/calling-a-function-when-ng-repeat-has-finished – XPD Oct 09 '16 at 19:28
  • Is there any better way to modify the transcluded clone if it contains another transcluded directive (which is rendered as a comment)? – XPD Oct 09 '16 at 19:29
  • tell me why do you need transclusion? – Max Koretskyi Oct 09 '16 at 19:30
  • Im trying to add the content of this directive into a template which can be done by a templateUrl, but I needed to access the content of the directive and modify it before attaching it to a templateUrl html. – XPD Oct 09 '16 at 19:34
  • do you use `ng-transclude` directive in the template? – Max Koretskyi Oct 09 '16 at 19:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/125295/discussion-between-xpd-and-maximus). – XPD Oct 09 '16 at 19:38

1 Answers1

2

You don't get .slide divs because at the time your code inside transclude is being executed:

el.after(clone);
scope.showCurrent(scope.slider.currentIndex);

the linking functions of the inner content, particularly ng-repeat's linking function, has not been executed yet. It's inside this linking function a watcher is added for the slides.

Even if you wait until the linking functions get executed, as in here:

transclude(scope, function (clone) {
    el.after(clone);
    scope.showCurrent(scope.slider.currentIndex);
})
// here the linking functions of the `clone` have already been executed

.slide divs are still not available until the first digest loop runs.

After your update

You definitely don't need this part here

transclude(scope, function (clone) { 
    el.after(clone); 
    scope.showCurrent(scope.slider.currentIndex); 
})

because it will be different clone that the one processed by ng-transclude and ng-transclude will take care of compiling and linking the content. You have to wait until digest loops runs and ng-repeat renders the div .slider elements. For that, use $timeout:

$timeout(function() {
    scope.showCurrent(scope.slider.currentIndex);
}); 
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488