So I am looking to move my library of plugins over to Angular wherever possible just to keep things consistent. The problem I am running into is getting directives to run after after any directives on its children have run.
Just to give a little bit of clarity, the goal here is to make it easy for our integrators (CSS/HTML only team members) to add dynamic functionality to items simply by tagging it with a feature. Currently they do this via a data-features
attribute. For instance, for an image slider they might tag a UL with a data-features="imageSlider"
attribute to make that UL a slider.
Along those lines, I am working on moving that image slider module over to angular. I want my integrators to be able to write something like:
<ul image-slider>
<li slide>
My Slide 1
</li>
<li slide>
My Slide 2
</li>
<li slide>
My Slide 3
</li>
</ul>
And I can turn that into an image slider dynamically. The above works fine, however if the markup looks like this:
<ul image-slider>
<li slide ng-repeat="slide in data.slider.slides">
My Slide {{$index}}
</li>
</ul>
Then the ng-repeat
doesn't finish before the image-slider
directive runs, which means I do not have access to all of the slides to work my magic.
Is there a way I can tell the image-slider
directive to wait for any directives inside of it to finish before firing?
I have read the following questions already:
None of these seem to have an answer to this problem so I figured I would put together a much more succinct question in the hopes of finding an answer.
I suggest a much simpler approach. Use the $timeout
function. If you set the $timeout
to zero, it will run exactly after everything has ran:
app.directive("imageSlider", [ '$timeout', function($timeout) {
return function(scope, element, attrs)
{
// your data is defined in scope.data.slider.slides
$timeout(function()
{
// This code will run whenever the page has finished processing
// So it will run after ng-repeat has finished
}, 0);
}
}]);
So the easiest way to do this is to use directive to directive communication between slide directive and the image-slider directive. Here is what you do:
app.directive("imageSlider", [ '$log', function($log) {
return {
scope: {
},
controller: function($scope) {
$scope.slides = [];
// this is a normal controller method that is NOT exposed to other directives
$scope.startGallery = function() {
};
// this method will be exposed to directives that require imageSlider
this.addSlide = function(slide) {
$scope.slides.push( slide );
}
}
};
} ]);
app.directive('slide', [ '$log', function($log) {
return {
require: "^imageSlider",
link: function($scope, elem, attribs, ctrls ) {
ctrls.addSlide( $scope );
}
};
} ] );
This way imageSlider can provide slide an interface to communicate through. Notice the difference in this.functionName vs $scope.functionName. The former being a way to expose methods to other directives.