3

I can't seem to add a controller after I bootstrap AngularJS. The exception I get indicates that the passed controller function is not a function. However, in the Chrome debugger it shows as the expected function.

(I realize that I am not using the declarative style of initializing AngularJS, I am exploring the framework.)

Exception

Error: Argument 'MediaLoaderController' is not a function, got undefined
    at Error (<anonymous>)
    at $a (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:16:453)
    at qa (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:17:56)
    at $get (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:52:219)
    at http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:43:348
    at m (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:6:494)
    at i (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:43:213)
    at e (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:39:307)
    at e (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:39:324)
    at e (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js:39:324) angular.min.js:62
(anonymous function) angular.min.js:62
$get angular.min.js:52
$get.e.$apply angular.min.js:88
(anonymous function) angular.min.js:16
d angular.min.js:27
c angular.min.js:16
rb angular.min.js:16
Bootstrapper.instance.bootstrapAngularJS bootstrapper.js:19
(anonymous function) slide_template_angularjs.jsp:20
x.Callbacks.c jquery.js:3048
x.Callbacks.p.fireWith jquery.js:3160
x.extend.ready jquery.js:433
q

HTML

<html>
    <head>
        <title></title>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>        
        <script src="/js/bootstrapper.js"></script>
        <script language="JavaScript">

            var bootstrapper = null;
            var controllerLibrary = null;

            $(document).ready( function(){
                bootstrapper = new Bootstrapper();
                controllerLibrary = new ControllerLibrary(); 

                bootstrapper.bootstrapAngularJS();
                bootstrapper.myModule.controller( "MediaLoaderController", controllerLibrary.MediaLoaderController );               
            });
            </script>
    </head>
    <body>
        <div ng-controller="MediaLoaderController">
            {{status}}
        </div>
    </body>
</html>

JavaScript

function Bootstrapper() {

    var instance = new Object();

    instance.myModule = null;
    /*
     * Bootstrap AngularJS and initialize myModule
     */
    instance.bootstrapAngularJS = function() {
        instance.myModule = angular.module('myModule', []);
        angular.bootstrap(document, ['myModule']);
    };

    return instance;
}


function ControllerLibrary() {
}

ControllerLibrary.prototype.MediaLoaderController = function($scope) {
    $scope.status = "loading";
};
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
Guido Anselmi
  • 3,872
  • 8
  • 35
  • 58
  • It works if you define `MediaLoaderController` globally (`function MediaLoaderController () { ... }`), but I'm not sure that's what you want. – Langdon Oct 02 '13 at 20:48
  • @Langdon: Thanks. Yeah not really. Trying to experiment with how to organize and execute stuff. All I can think is that AngularJS is 'cheating' somehow and not really taking the function reference from the call to controller(). – Guido Anselmi Oct 02 '13 at 20:54

1 Answers1

3

You have to register the controller before bootstrap happens, otherwise AngularJS can't find the controller and throw the error. See the working plunker here. Extract below.

function Bootstrapper() {
    var instance = new Object();
    instance.myModule = angular.module('myModule', []);
    instance.bootstrapAngularJS = function() {
        angular.bootstrap(document, ['myModule']);
    };
    return instance;
}

$(document).ready( function(){
    bootstrapper = new Bootstrapper();
    controllerLibrary = new ControllerLibrary(); 
    bootstrapper.myModule.controller( "MediaLoaderController", controllerLibrary.MediaLoaderController );               
    bootstrapper.bootstrapAngularJS();
});
Buu
  • 49,745
  • 5
  • 67
  • 85
  • Suppose we did want to add the controller after starting angular (for example the ng-controller node did not exist at first, but was added later by some AJAX outside of Angular), could we then restart Angular to find new controllers? – Wouter Oct 27 '14 at 09:08
  • 1
    You can register a controller any time, but if AngularJS can't find it when AngularJS needs it, then there will be an error. As long as the code to lookup the controller happens *after* the controller is registered, you'll be fine. – Buu Oct 27 '14 at 22:02