I have a very simple requirejs and angular demo app. When I run the code, it's as if angular doesn't register the homeController (even tho the file does run and outputs "Hello from home controller"). It's frustrating to get little to no debug info on how to solve this. Any help would be greatly appreciated!
On my local machine, I am getting this error message:
"Error: [ng:areq] Argument 'HomeController' is not a function, got undefined"
On Plnkr I am getting a different message:
Error: [ng:areq]
This is the plnkr link http://plnkr.co/edit/zNVIYckX5dAzV3CpEzXv?p=preview
index.html
<body ng-app="app">
<div ng-controller="HomeController">
{{message}}
</div>
<script src="http://requirejs.org/docs/release/2.1.14/minified/require.js" data-main="main.js"></script>
</body>
main.js
require.config({
paths: {
"jquery": '//code.jquery.com/jquery-2.1.1.min',
"angular": '//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular.min',
"angular.route": '//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.20/angular-route.min'
},
shim: {
"angular": { deps: ["jquery"], exports: "angular" },
"angular.route": { deps: ["angular"], exports: "angular.route" },
},
deps: ["app", "routes"]
});
//kickoff the app
require(["app", "routes" ]);
app.js
define(["angular"], function () {
$("body").append("hello from app<br/>");
return angular.module("app", ['ngRoute']);
});
routes.js
define("routes", ["app", "angular.route", "homeController"], function(app) {
$("body").append("hello from angular.route<br/>");
app.config(function($routeProvider, $locationProvider) {
$("body").append("$routeProvider<br/>");
$locationProvider.html5Mode(true);
$routeProvider.when("/", {
templateUrl: "home/home.html",
controller: "HomeController"
})
});
});
homeController.js
define("homeController", ["app"], function (app) {
$("body").append("hello from home controller<br/>");
app.controller("HomeController", function ($scope) {
$("body").append("hello from home controller body<br/>");
$scope.message = "message from home controller";
});
});
github demo: https://github.com/zouhenry/angular-requirejs-demo
I have figured out the problem and hope this answer will help others out there.
The problem is when dom is ready, angular will parse the html and will try to bind HomeController to the ng-controller directive, even before the homeController file has been loaded by requirejs.
So what I ended up doing was removing the ng-app directive from
index.html. This prevented angular from automatically binding to directives when the page is loaded (we will programmatically bind the application to the page later)
<body ng-app="app">
Since I removed ng-app from the Html itself. I need to programmatically bind the the app to html.
I did this with in the Main.js
//kickoff the app
require(["app", "routes" ], function(){
angular.bootstrap(document, ["app"]);
});
Last thing I did was move the require.js to the head instead of the keeping it in the body (not sure if this was necessary). This is the revised index.html
<html>
<head>
<script src="http://requirejs.org/docs/release/2.1.14/minified/require.js" data-main="main.js"></script>
</head>
<body>
<div ng-controller="HomeController">
{{message}}
</div>
</body>
</html>
Yea, me too took long time to figured it out.
This is mainly because requirejs won't register all the controllers
initially to the app since it is lazily loading the files and the
controllers
The things you need to do is, if you want to call any of the controller, you need to register manually with the modules. So you won't get the issue.
Example
app.config(function($routeProvider, $locationProvider,$controllerProvider) {
//To register the controller which will be load on demand (which will be loaded lazily)
app.registerController = $controllerProvider.register;
// To register the following which will be loaded lazily later for future use
// * Constant - app.regiser.value - To register constant
// * Factory - app.regiser.factory - To register factory
// * service - app.regiser.service - To register service
app.$register = $provide;
// To register filter
app.registerFilter = $filterProvider.register;
// To register directive which will be loaded lazily
app.registerDirective = $compileProvider.directive;
}
app.registerController("HomeController", function ($scope) {
$("body").append("hello from home controller body<br/>");
$scope.message = "message from home controller";
});
var app = angular.module("app");
app.$register.factory('appService',function(){
});
Or
You can go with some third party plugins like AngularAMD, $couchPotatoProvider.