Reputation: 4291
I have a directive called "connection" that draws a connecting line between two other divs given the ids of the divs. The ids are passed indirectly via some scope data.
My "connection" directive needs to get the bounding rectangle of the named DOM elements so it can draw a connecting line between them with the appropriate coordinates.
In my directive's link function though, calling getElementById()
for these ids returns undefined. This is because in the DOM, the ids of those elements are still in the form of id="intf-{{intf.id}}
" when my connection directive's link function is run (i.e., they haven't been interpolated yet).
The divs in question were generated with ng-repeat and had their ids assigned dynamically.
How can I make my directive efficiently wait for the element ids to go through interpolation and then immediately notify my directive so that it can update its template and/or scope data?
Alternatively, can I force the interpolation to occur immediately so that getElementById()
would work and then continue my link function?
I've seen that you can use attrs.$observe()
to know when your own attr has updated, but I can't see how to do that with an arbitrary element's attrs. In fact, I can't even get the element until its name is interpolated, since that is the only way I can identify it.
As an incomplete solution, the previous developer who worked on this code added something like this:
link: function( scope, element, attrs ) {
var deferUntilElementsExist = function( newVal, oldVal, cb ){
var sourceElement = document.getElementById(scope.connection.source().id);
var targetElement = document.getElementById(scope.connection.target().id);
if( !sourceElement || !targetElement ) {
$timeout( function(){ deferUntilElementsExist( newVal, oldVal, cb ); }, 0 );
return;
}
updatePath();
if (cb) {
cb( newVal, oldVal );
}
};
This sort of works, but the lines appear very slowly, like 5 per second or so, even when there are hundreds of them, as if it's processing one line per update cycle or something like that.
Thanks.
Upvotes: 2
Views: 976
Reputation: 4291
The comment from @pixelbits led me in the right direction. Adding the third parameter to $timeout() set to false, which prevents an $apply() after each invocation, made the "Incomplete Solution" work much faster.
link: function( scope, element, attrs ) {
var deferUntilElementsExist = function( newVal, oldVal, cb ){
var sourceElement = document.getElementById(scope.connection.source().id);
var targetElement = document.getElementById(scope.connection.target().id);
if( !sourceElement || !targetElement ) {
$timeout( function(){ deferUntilElementsExist( newVal, oldVal, cb ); },
0, false ); // Added third parameter here set to false
return;
}
updatePath();
if (cb) {
cb( newVal, oldVal );
}
};
Upvotes: 1