3

I have a web app in wich i like to insert my own custom directives, and in order to do that i have defined a new module where i define those new directives (only 1 for now) so i can reuse in the future. The problem comes when AngularJS try to instantiate the new module, i got the following error

(i put only the first part of the log so it don't get too dificult to read):

Uncaught Error: [$injector:modulerr] Failed to instantiate module tangoInfinito due to:
Error: [$injector:modulerr] Failed to instantiate module custom.modal due to:
Error: [ng:areq] Argument 'directiveFactory' is required
http://errors.angularjs.org/1.5.9/ng/areq?p0=directiveFactory&p1=required
    at http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:68:12
    at assertArg (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:1937:11)
    at $CompileProvider.registerDirective [as directive] (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:7845:7)
    at runInvokeQueue (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:4654:35)
    at http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:4662:11
    at forEach (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:325:20)
    at loadModules (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:4644:5)
    at http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:4661:40
    at forEach (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:325:20)
    at loadModules (http://localhost/tangoinfinito.com.ar/js/Dependencies/angular/angular.js:4644:5)

also here is my new module:

(function() {

    var app = angular.module("custom.modal", []);

    // Esta directiva es para generalizar los Modals de Bootstrap 3. No debe ser usada de manera individual,
    // sino como esqueleto de Modals personalizados en otras directivas.
    var bootstrapModal = function() {
        return {
            restrict: "E",
            template: 
            "<div class='modal fade' tabindex='-1' role='dialog' aria-labelledby='modalTitle'>" +
                "<div class='modal-dialog' role='document'>" +
                    "<div class='modal-content'>" +
                        "{{ htmlModalContent }}" +
                    "</div>" +
                "</div>" +
            "</div>",
            controller: "ModalController"
        }
    };

    var ModalController = function($scope) {
        $scope.htmlModalContent = "";
    };

    app
    .controller("ModalController", ModalController)
    .directive("bootstrapModal", bootstrapModal)
    ;

})();

I hope you can help me, i search a lot trough the web and i found almost nothing about this error. Thanks in advance.

EDIT: new error after the Phil answer:

Error: [$compile:ctreq] Controller 'bootstrapModal', required by directive 'loginModal', can't be found!

i left you my "loginModal" directive:

(function() {

    var app = angular.module("tangoInfinito");

    var loginModal = function() {
        return {
            require: "bootstrapModal",
            link: function(scope, element, attr) {
            scope.htmlModalContent = /* Here comes the template to be inside the modal (the modal body and footer) */
            },
            template: "<bootstrap-modal></bootstrap-modal>"
        }
    };

    app.directive("loginModal", loginModal);

})();

Augusto Herbel
  • 192
  • 2
  • 13

4 Answers4

3

You are trying to use ModalController and bootstrap_modal before they are defined.

Move their definitions to the top, ie

var bootstrap_modal = function () { ... }
var ModalController = function($scope) { ... }

app
.controller("ModalController", ModalController)
.directive("bootstrap-modal", bootstrap_modal)
;

or define them as functions to take advantage of hoisting, eg

function ModalController($scope) {
  // etc
}

function bootstrap_model() {
  // etc
}

Also, your directive name should be bootstrapModal, ie

app.directive('bootstrapModal', bootstrap_modal)

Update

As for your new error, it seems to relate to $compile. Does your element have both directives, eg <bootstrap-modal login-modal>?

That's what require means but I think you're using it incorrectly.

Phil
  • 157,677
  • 23
  • 242
  • 245
  • i have a new error now... i'm going to post it in the question – Augusto Herbel Feb 14 '17 at 04:36
  • I just only have "" in my html file... and define the html code that goes inside the modal (the body and footer) in the htmlModalContent variable of ModalController... this is my first directive so it might be all wrong... also i think if use require i was abble to use that directive inside the template of the directive that requires it – Augusto Herbel Feb 14 '17 at 04:51
  • @AugustoHerbel No, you do not need `require` to use another directive. I suggest you read the [**documentation**](https://docs.angularjs.org/api/ng/service/$compile#-require-) very carefully – Phil Feb 14 '17 at 04:53
  • thanks @Phil that was the problem... thank you very much for the help... sry i can't vote for your answer, i still do not have the necesary reputation – Augusto Herbel Feb 14 '17 at 04:58
1

Phil and Faizal have the answers for you above ^^. I have a pre-formatted version below for ease of use. It's worth noting to be very careful when using capitalized directive declartions and all types of definitions for angular API namespaces. It's safe to stick to regular camelCase, it can be one of the tricky gotcha's for those new to angular.

Here are the some of the details

& More naming tips

(function() {

var app = angular.module("custom.modal", []);


app
.controller("modalController", modalController)
.directive("bootstrapModal", bootstrapModal)
;

// Esta directiva es para generalizar los Modals de Bootstrap 3. No debe ser usada de manera individual,
// sino como esqueleto de Modals personalizados en otras directivas.
function bootstrapModal() {
    return {
        restrict: "E",
        template: [
            "<div class='modal fade' tabindex='-1' role='dialog' aria-labelledby='modalTitle'>",
                "<div class='modal-dialog' role='document'>",
                    "<div class='modal-content'>",
                        "{{ htmlModalContent }}",
                    "</div>",
                "</div>",
            "</div>"
        ].join(''),

        controller: "modalController"
    }
};

function modalController($scope) {
    $scope.htmlModalContent = "";
};

})();
Community
  • 1
  • 1
cmswalker
  • 371
  • 3
  • 4
  • 1
    also, one of the other issues you were having was a typo in your directive return: `restric: "E"` should be `restrict: "E"`. It is fixed in the snippet above ^^ – cmswalker Feb 14 '17 at 04:53
  • ooh i don't notice that... i fix that but the error are still happening... i don't know why angular get "bootstrapModal" as a Controller since i have defined it as directive... – Augusto Herbel Feb 14 '17 at 04:56
  • It should be registering as a directive. When you provide the controller property inside your directive, you're allowing the directive to get access to the controller's scope. This is sometimes a quick fix, but can be avoided by giving isolate scope to a directive and simply passing properties down from your controller to your directive in the html. Here is a bin that is on it's way to what you need. https://jsbin.com/kukucocito/1/edit?html,js,output – cmswalker Feb 14 '17 at 05:04
0

This a common problem when you use function expression syntax i.e

var ModalController = function($scope) { ... }

As, this prevents you from taking the advantage of JavaScript hoisting. Which can be achieved if you write your function as

function ModalController($scope){....}

Further, you should visit this JavaScript function declaration syntax: var fn = function() {} vs function fn() {} link for detailed difference of the same.

Also, Mozilla docs explains hoisting in detail.

Community
  • 1
  • 1
faizal vasaya
  • 517
  • 3
  • 12
0

In my case I was deleting a module and deleted its definition but forgot to remove the call to angular.module('',[]).directive():

angular.module('foo.bar.baz', []).directive('someView', someView /* undefined */);

Removing '.directive(...)' fixed the problem.

Alexander Taylor
  • 16,574
  • 14
  • 62
  • 83