4

The function that I'm providing to define my directive is never called. It used to work fine but suddenly stopped working and I have no idea why.

Here's my directive:

portalApp.directive('contactPanel', function () {
    console.log("NEVER SHOWN!");
    return {
        restrict: 'AE',
        replace: 'true',
        templateUrl: 'partials/account/contactPanel.html',
        scope: {
            contact: '=contact',
            primaryRoleName: '@',
            roleName: '@',
            primary: '=primary',
            locations: '=locations'
        },
        controller: function (userService, $rootScope, $scope) {
            ...snip...
        }
    };
});

and here an example of its use:

<contact-panel contact="user.account.contacts.billing" role-name="billing"
               locations="locations"></contact-panel>

Note that I'm using the correct casing, i.e. camel-case in JS and hyphenation in HTML.

The key clue is that the message that's logged in the second line (i.e. 'NEVER SHOWN!') never shows up in the console. If I log a message immediately before the directive declaration then that shows up, so this code is being executed by the interpreter, but the framework is just never using my declaration.

I'd love to have an answer obviously, but I'd also love to hear of some approaches to debug this kind of problem.

7
  • any error in console ? Commented Sep 15, 2015 at 2:09
  • Are there any errors in the console? Are you testing a page where the contact-panel is present on? Commented Sep 15, 2015 at 2:09
  • use console.log in controller instead of outside Commented Sep 15, 2015 at 2:11
  • No, there's no error in the console. As far as I can see, there's no point in logging in the controller because we know that the code that defines that controller is never called, but I did it anyway and confirmed that it was not shown in the console. Commented Sep 15, 2015 at 2:15
  • Seems positive then that the html you have there isn't present on the page, or you've added it in a way foreign to Angular (dom manipulation that isn't compiled). Commented Sep 15, 2015 at 2:16

2 Answers 2

8

I can see only 2 possibilities that would exhibit the behavior you described. Either the HTML with the directive was not compiled or the directive is not registered.

The "not compiled" case could be because the directive is used outside of the Angular app, for example:

<div ng-app="portalApp">
 ...
</div>
...
<contact-panel></contact-panel>

Or, if you added the HTML dynamically, but did not $compile and link it.

The "not registered" case could be due to re-registration of the app's module. In other words, you might have the following case:

var portalApp = angular.module("portalApp", []);
portalApp.directive("contactPanel", function(){...});

// then elsewhere you use a setter:

angular.module("portalApp", []).controller("FooCtrl", function(){});    
// instead of the getter:
// var app = angular.module("portalApp");

The second call to angular.module("portalApp", []) removes the previous registration of .directive("contactPanel", ....

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

2 Comments

The ng-app attribute is defined on the <html> element and the <contact-panel> element is beneath that. I've just searched for the second possibility and that doesn't see to be the case either. In desperation I've begun debugging Angular itself. I noticed that the directive() function adds the call to an array called portalApp._invokeQueue, presumably for it to be invoked later. I set a breakpoint in a button's click-handler. I pressed the button well after the page has rendered and inspected portalApp._invokeQueue. I found that it still has the entry for contactPanel in it.
..continued... So it seems as though invocation of the invokeQueue is not completed. I have no idea why this would happen. As I wrote earlier, no errors are reported.
1

I figured out the cause of this problem. At some point I must've accidentally moved the directive into a configuration block like this:

portalApp.config(function ($stateProvider, $urlRouterProvider) {
    portalApp.directive('contactPanel', function () {
        console.log("NEVER SHOWN!");
        return {
            ...snip...
        };
    });
});

Once I moved it back out of the configuration block and into the global scope the directive immediately rendered as it should.

The reason why this doesn't work is that angular runs the configuration code after it's run the directives, like this:

runInvokeQueue(moduleFn._invokeQueue);    // runs directives
runInvokeQueue(moduleFn._configBlocks);   // runs config blocks

So things added to the _invokeQueue (which the directive() function does) from within a config block will never be executed.

Thank you to all those who tried to help.

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.