If you enclose that code snippet within the $timeout
function in a link function, it will ensure that your element is fully rendered as the $timeout only runs after the current digest cycle is finished (assuming you have already set the id before the current digest cycle). Also, remember to utilize the third argument (set to false) to disable the digest cycle run if no scope updates are to be performed inside the timeout.
Another approach is to implement a one-time watch if you are uncertain about when the id is set, especially when it is set asynchronously (e.g., divid="{{someId}}"
and someId
is populated asynchronously).
Furthermore, there exists a non-standard, private property of a scope referred to as $$postDigest
, but bear in mind that since it is an internal property, its implementation may change in future versions. Therefore, use this at your own discretion.
angular.module('app', []).directive('direct', function($timeout) {
return {
scope: {
divid: '@'
},
restrict: 'EA',
template: '<div id="{{divid}}"></div>',
link: function(scope, element) {
console.log('Before digest-->', element.find('div').attr('id'));
//using timeout
$timeout(function() {
console.log('In timeout-->', element.find('div').attr('id'));
}, false);
//Using non standard postdigest
scope.$$postDigest(function() {
console.log('In postdigest-->', element.find('div').attr('id'));
});
//Setting up a onetime watch
var unWatch = scope.$watch(function() {
return element.find('div').attr('id');
}, function(val) {
if (val) {
unWatch();
console.log('One time watch-->', element.find('div').attr('id'), val);
}
})
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
<div ng-app="app">
<direct divid="someid"></direct>
Nothing much here, See the console
</div>