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:)

+3


source to share





All Articles