12

In my angular app, directives are working fine during the first visit, but once a page been visited twice, all the directive link function gets called twice too. Say I am on page A, click a link to go to page B and then back to page A, all directives on page A will execute the their link function twice. if I refresh the browser it will become normal again.

Here is an example where the console.log will output twice when the second visit.

  @app.directive 'testChart', ["SalesOrder", (SalesOrder) ->
    return {
      scope: {options: '='}
      link: (scope, elem, attrs) ->
        console.log("............checking")
        SalesOrder.chart_data (data) ->
          Morris.Line
            element: "dash-sales"
            data: data
            xkey: 'purchased_at'
            ykeys: ['total']
            labels: ['Series a']
    }
  ]

Any idea?

Update

My Route

when("/dash", { templateUrl: "<%= asset_path('app/views/pages/dash.html') %>", controller: DashCtrl }).

so my chart is duplicated enter image description here

15
  • do you have two directives on the page at the same time? Or are you using page animations? Commented Jan 10, 2014 at 9:02
  • That's right. When you leave the page (or do you mean route?), then elements are removed from the DOM, and destroyed. When you view that page/route again, then the template is recompiled and the link function run again. And then the directives added when you view the page/route again. What specific problem is this causing you? Commented Jan 10, 2014 at 9:04
  • 1
    Wild guess: is the chart in a ng-repeat and is the data kept in a service (and refreshed when the view is (re)loaded)? Commented Jan 10, 2014 at 9:24
  • 1
    Do you possibly have the controller for A referenced twice? i.e. Once on the page and once in the route? Commented Jan 10, 2014 at 20:12
  • 2
    In my case, I was calling $compile inside link. Commented Mar 22, 2014 at 8:45

5 Answers 5

19

also make sure you are not including your directive in your index.html TWICE!

Sign up to request clarification or add additional context in comments.

3 Comments

This answer can not be upvoted enough. If you're using chrome and have two script tags, it will only make the request once, but run the code twice. Do not get fooled like I did. Check your html.
Oh, snap... I can't believe this shit. After trying all types of e.stopPropagation(); and nothing helped, this was it for me! Even stranger though, e.stopPropagation(); actually worked - but only if the anonymous event function did not include param e which gives (correctly) a console error instead..... TGIF.
Ouch, I just got caught out by this one too. Somehow an old version of the directive was cached and was calling alongside the current one. Thanks for saving me another half hour of debugging and furiously scratching my head.
5

I had this exact same problem. After a loooooong time digging around I found that I hadn't used the correct closing tag which resulted in the chart being called twice.

I had

<line-chart><line-chart>

instead of

<line-chart></line-chart>

Comments

3

The link() function is called every time the element is to be bound to data in the $scope object.

Please check if you are fetching data multiple times , via GET call. You can monitor the resource fetching via Network tab , of chrome debugger.

A directive configures an HTML element and then updates that HTML subsequently whenever the $scope object changes.

A better name for the link() function would have been something like bind() or render(), which signals that this function is called whenever the directive needs to bind data to it, or to re-render it.

Comments

0

Maybe this will help somebody...

I had a problem with directive transclude, I used a transclude function which was adding child elements and also at the same time I forgot ng-transclude in directive template. Child elements were also directives and their link function was called twice!

Spent some time on this one..

More in details:

I had a "main" directive and "child" directives, idea was to use one inside another, something like that:

main
    child
    child

So problem was that link of "child" directive was called twice, and I didn't understand why,

Turned out I had ng-transclude in "main" directive template (I am posting it as it is in PUG format, sorry for that):

md-card(layout-fill)
  md-card-content(flex)
    .map-base(id="{{::config.id}}", layout-fill)
      ng-transclude

and also in link function of "main" directive I called transclude function:

link: function($scope, $element, $attrs, controller, transcludeFn) {
  $element.append(transcludeFn());
}

I think I just tried different combinations and forgot about that, visually everything was ok, but link was called twice and code was running twice and logic was broken..

So problem is that you can't have both and you have to choose one of the ways.

Hopefully now it is more clearer.

1 Comment

I forgot ng-transclude in directive template - Was adding it enough to fix it? It's not entirely clear from your answers. For the record: This question was sent to the Low Quality Posts queue, which means someone thought that this didn't answer the question. Please edit your post to make it clearer what your solution was.
0

In my case I had a main-nav and sub-nav that both called a directive by its name attribute. Since the first instance already set the scope needed the second sub-nav the 2nd call wasn't needed. Incase anyone has a similar issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.