2

I have an angularJS app with nested ui-view like this (simplified version):

index.html

<html ng-app="admineConsoleApp">
<head> </head>
<body>
  <div>
      <div ui-view=""></div>
  </div>
</body>
</html>

And my main wrapper to inject other views:

main.html

<div id="page-wrapper">
    <div ui-view=""></div>
</div>

And my config:

    ....
    $urlRouterProvider.otherwise('/');
    $urlRouterProvider.when('', '/');

    $stateProvider
        .state('dashboard', {
            url: '',
            templateUrl: 'views/main.html'
        })
        .state('dashboard.home', {
            url: '/',
            controller: 'HomeController as home',
            templateUrl: 'views/home.html'
        })
        ....

Everything worked fine until I used a directive to handle a modal pop up. This is my directive:

subscription.directive.js

angular
    .module('adminConsoleApp')
    .directive('modalDetail', modalDetail);

function modalDetail() {
    var directive = {
        restrict: 'EA',
        scope: {
            modalContainer: '=?',
            callbackbuttonleft: '&ngClickLeftButton',
            callbackbuttonright: '&ngClickRightButton'
        },
        templateUrl: 'scripts/directives/subscription/modal.subscription.template.html',
        transclude: true,
        controllerAs: 'home',
        controller: 'HomeController',
        bindToController: true
    };

    return directive;

I also noticed that every functions inside my controller is actually running twice. And of course I need the controllerAs because the stateProvider refer to my controller's alias and because directive template use controller's alias. With this configuration the HomeController will be ran twice, but if I remove the controllerAs the directive don't work (of course) but the controller run only one time. This is the console.log(this); for my controller instance:

console log for 'this' instance

If you notice, the first this refer to my initial controller instance. The second one in just an object with directive reference. I already followed the most common solutions like:

  • remove ng-controller param inside div element
  • with/without manual bootstrap
  • check for multiple directive instance or reference

The only thing I didn't tried yet is to wrap the controller logic for directive modal directly inside the directive itself (I mean: avoid use of controller: HomeController and define a new one). But I'd like to know if I can keep things like actually they are and apply a solution to avoid controller running twice.

Note: this behaviour is annoying, but things works fine (after the second call). I just want to know a nice solution to ensure the directive does not run controller twice.

5
  • Which functions from your controller run twice? I'm pretty sure they are in your templates and run because of $digest cycle Commented Sep 13, 2016 at 10:50
  • for example, like I said, the console.log(this) will fire 2 times. If you click on "console log for this instance" you will notice 2 logs. Commented Sep 13, 2016 at 10:56
  • I've re-read your question, so you have the route that uses controller: 'HomeController as home', and then you have directive controller: 'HomeController', of course your functions are going to run twice, controllers aren't singletons Commented Sep 13, 2016 at 11:00
  • so you suggest to separate things? I mean using another controller for directive (a new one or a function of it). Commented Sep 13, 2016 at 11:21
  • My guess is that the directive don't share much logic of the main controller so frankly yes, have it separated. If directive requires controller then it's better to have specific one for the directive, and use service/factory when you need two way data-binding with other controllers. Commented Sep 13, 2016 at 11:24

2 Answers 2

1

In angular all usage of same controller is independent instances. Your controller function is just controller constructor.

All code, which should run only once, you should place run and config blocks ( and mb resolves of ui-router and services(using any kind of cache)).

It's impossible to avoid controller code running twice in your situation.

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

Comments

0

SOLVED: just override home controller inside directive and using a different controller instead. Something like this:

function modalDetail() {
    var directive = {
        restrict: 'EA',
        scope: {
            modalContainer: '=?',
            callbackbuttonleft: '&ngClickLeftButton',
            callbackbuttonright: '&ngClickRightButton'
        },
        templateUrl: 'scripts/directives/subscription/modal.subscription.template.html',
        transclude: true,
        controller: function() {
           // your implementation here
        }
    };

    return directive;

}

Of course, change the params template references in order to make it works.

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.