Nested directive lifecycle doesn't execute in expected order when using $ compile and adding to DOM for the first time
What am i trying to do
I have the following directive structure:
<dashboard>
<widget>
<timer></timer>
</widget>
<widget>
<chronometer></chronometer>
</widget>
</dashboard>
Where dashboard
, widget
, timer
and chronometer
- all user directives that I wrote.
The basic idea is that I want the directive to dashboard
keep track of everything widgets
it has. When a widget
equals $compile
d and is added to the DOM from dashboard
, it automatically adds itself to dashboard
by calling a method addWidget(widget)
from a function widget
link
that is exposed by the controller dashboard
.
The directive widget
knows how to minimize itself, close itself, set a title, etc., and also has a method register
on its own controller
that accepts widget metadata information (such as the name and version of the widget).
In widgets, timer
both chronometer
require widget
and call the register({name: 'timer', version: '0.1'})' which exists in the
widget` controller function.
Finally, dashboard
link
there is a method in the function addWidget()
that allows users to add widgets timer
and chronometer
.
For this example, I'm going to assume that we just want to add a directive timer
to the toolbar:
// dashboard.directive.js
function link($scope, $elem, $attrs) {
$scope.addWidget = function () {
var widget = $compile('<widget><timer></timer></widget>')($scope);
angular.element($elem[0].querySelector('.widget-container')).append(widget);
}
}
When the function is called $addWidget
, the timer widget is successfully added to the dashboard, I can start / stop / reset the timer and the directive widget
registers the directive timer
and then the directive is widget
registered with the directive dashboard
. I have 100% confirmed that this works great.
Directive life cycle: what I expect
Here's what the DOM looks like:
<dashboard> <!-- the dashboard already exists on initial bootstrap -->
<widget> <!-- the widget and timer are added dynamically by the dashboard -->
<timer></timer>
</widget>
<widget> <!-- the widget and chronometer are added dynamically by the dashboard -->
<chronometer></chronometer>
</widget>
</dashboard>
From what I understand in the life cycle of Angular directives, directives should be structured like this:
dashboard controller() called
dashboard link() called
widget controller() called
timer controller() called
timer link() called
widget link() called
If the widget and timer are added to the DOM internally dashboard
as described in the snippet above dashboard.directive.js
.
Directive lifecycle: what do I get (sometimes)
However, sometimes when I add a timer to the dashboard for the first time, it doesn't. ... After I added a bunch of statements console.log
inside functions controller
and link
for directives dashboard
, widget
and timer
however, I found that directives are sometimes built in the following order:
dashboard controller() called
dashboard link() called
// Why is this happening:
widget controller() called
widget link() called
timer controller() called
timer link() called
What's even more puzzling is that this seemingly non-standard composition only happens the first time I add a widget to the DOM. The second time, when I add the same widget, everything happens in the correct order.
What am I doing wrong? I am using Angular 1.2.26 (unfortunately I have to use this version). Thanks for the help:)
source to share
No one has answered this question yet
Check out similar questions: