XPD XPD - 1 month ago 19
AngularJS Question

How to modify the transcluded content of a custom directive?

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

Answer

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);
});