I'm new to all Angular World, and i'm facing a problem managing the directives.
I'm working on a project that uses Tabs, and i want to extend its functionality to handle overflowed tabs when window size is narrower that the width of all my tabs, so i need to calculate some dimensions of elements to achieve this. The tabs are built from an Object in $scope, the problem is that the directive that calculates the dimensions is run before the view is fully compiled.
Plnkr Link: http://plnkr.co/edit/LOT4sZsNxnfmQ8zHymvw?p=preview
What i've tried:
I think that there is some AngularJs event, or property to handle this situation.
Please Guys Help :)
AngularJS does not seem to have reliable post-render callbacks for directives used within ng-repeat. [1]
Maybe you can solve this on CSS level by adding a "responsive" overflow-control element for specific screen widths.
Update: There now is a way to do this using nested $timeouts. See: http://lorenzmerdian.blogspot.de/2013/03/how-to-handle-dom-updates-in-angularjs.html
You can add a watch on the actual DOM elements in order to know when your ng-repeat is loaded into the DOM.
Give your ul an id, say #tabs
$scope.$watch(
function () { return document.getElementById('tabs').innerHTML },
function(newval, oldval){
//console.log(newval, oldval);
//do what you like
}, true);
I make a branch on your plunker, I I think this is what you were looking for
I change your directive to this
.directive('onFinishRenderFilters', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
});
}
}
}
});
Then on your HTML I added the directive
<li ng-repeat="tab in tabs" on-finish-render-filters>
And the last thing I put the code I want to run after the repeat finish
$scope.$on('ngRepeatFinished', function (ngRepeatFinished) {
$scope.tabs = [{
index: 1,
title: "Tab 1",
link: "/tab1/"
},{
index: 2,
title: "Tab 2",
link: "/tab2/"
},{
index: 3,
title: "Tab 3",
link: "/tab3/"
},{
index: 4,
title: "Tab 4",
link: "/tab4/"
}];
});
According to your comments, you already have a solution that works ... and its currently the only solution that I know of: $timeout.
The question is, what do you want to achieve? You want a callback when all rendering is done. Ok, good, but how can angular know this? In a modern app which you are apparently developing when using angular, a rerender can happen all time! A js event can occur where data is loaded from backend, even right after initializing the app, which leads to rerendering. A mouse movement by the user can trigger rerendering of elements, which are even outside of angulars scope because of CSS rules. Any time, a rerender can happen.
So, with these considerations what can angularJS tell you about when rendering is done? It can only tell you, when current $apply and/or $digest chain is processed aka the browser event queue is empty for now. Exactly that is the only information that angularJS knows of. And you use $timeout with a delay of 0 for this.
Yes, you are right, in a bigger appliataion, that can be tricky to a point where its not reliable anymore. But in this case, you should think about how you can solve this in another way. F.i. if a rerender happens later, there must be a cause, like new data that is loaded from the backend. If so, you know when the data is loaded and therefore a rerender happens and therefore you know exactly when you have to update your widths.