Reputation: 30356
Having created a very basic prototype AngularJS project, I wanted to migrate it to use RequireJS to load the modules. I modified my app based on the AngularAMD and AngularAMD-sample projects.
Now, when I access my default route I get:
Uncaught TypeError: Cannot read property 'directive' of undefined
I've been scratching my head as to why the dependency on 'app' is not being satisfied. If anyone can spot what I'm obviously doing wrong, it'd be much appreciated.
I've put the source code of my project here on GitHub, but here's the key parts:
main.js
require.config({
baseUrl: "js/",
// alias libraries paths
paths: {
'angular': '../bower_components/angular/angular',
'angular-route': '../bower_components/angular-route/angular-route',
'angular-resource': '../bower_components/angular-resource/angular-resource',
'angularAMD': '../bower_components/angularAMD/angularAMD',
'ngload': '../bower_components/angularAMD/ngload',
'jquery': '../bower_components/jquery/jquery'
},
// Add angular modules that does not support AMD out of the box, put it in a shim
shim: {
'angularAMD': ['angular'],
'ngload': [ 'angularAMD' ],
'angular-route': ['angular'],
'angular-resource': ['angular']
},
// kick start application
deps: ['app']
});
app.js
define(['angularAMD', 'angular-route', 'controller/login', 'controller/project_detail', 'controller/project_list'], function (angularAMD) {
'use strict';
var app = angular.module('cmsApp', ['ngRoute']);
app.constant('REMOTE_BASE_URL', "/cms/v2/remote");
app.constant('SERVER_ERROR_TYPES', {
authentication: 'Authentication',
application: 'Application',
transport: 'Transport'
});
app.constant('AUTH_ERROR_TYPES', {
invalidLogin: "INVALID_CREDENTIALS",
invalidToken: "INVALID_TOKEN",
noToken: "NO_TOKEN"
});
app.constant('AUTH_EVENTS', {
loginSuccess: 'auth-login-success',
loginFailed: 'auth-login-failed',
logoutSuccess: 'auth-logout-success',
notAuthenticated: 'auth-not-authenticated'
});
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
}).
when('/projects', {
templateUrl: 'partials/project-list.html',
controller: 'ProjectListCtrl'
}).
when('/projects/:projectId', {
templateUrl: 'partials/project-detail.html',
controller: 'ProjectDetailCtrl'
}).
otherwise({
redirectTo: '/projects'
});
}]);
return angularAMD.bootstrap(app);
});
And the file which the exception is being raised in: login_form.js
define(['app'], function (app) {
app.directive('loginForm', function (AUTH_EVENTS) {
return {
restrict: 'A',
template: '<div ng-if="visible" ng-include="\'partials/login.html\'">',
link: function (scope) {
scope.visible = false;
scope.$on(AUTH_EVENTS.notAuthenticated, function () {
scope.visible = true;
});
scope.$on(AUTH_EVENTS.loginFailed, function () {
alert("An error occured while trying to login. Please try again.")
scope.visible = true;
});
scope.$on(AUTH_EVENTS.logoutSuccess, function () {
scope.visible = true;
});
}
};
});
});
Upvotes: 2
Views: 6743
Reputation: 2305
You are loading 'controller/login' before the app itself was created.
Probably it is better to create a separate module like
define(['directive/login_form', 'service/authentication'], function () {
'use strict';
var loginModule = angular.module('loginModule', []);
loginModule.controller('LoginCtrl', ...
loginModule.directive('loginForm', ...
and then do something like
var app = angular.module('cmsApp', ['ngRoute', 'loginModule']);
Does that make sense?
UPDATE:
I am just thinking of another solution. Just remove 'controller/login' from your app define. Using angularAMD your controller should not be loaded anyway before you navigate to the specified url. Just remove it and your controller gets loaded on demand. That way, app will be defined! (Although I would still suggest to create multiple modules. It feels better to not have everything in the app module but have multiple modules for different responsibilities. Also much better for testing.)
angularAMD.route({
templateUrl: 'views/home.html',
controller: 'HomeController',
controllerUrl: 'scripts/controller'
})
Note the field controllerUrl.
Have a look here.
Upvotes: 6