David Findlay David Findlay - 2 months ago 16
AngularJS Question

Can't Find Controller from HTML

I'm working with a Play framwork project using angular-seed project as a basis. It creates an array of controllers and passes them into the angularjs instance I guess, somewhat different to other tutorials I've seen. When I try to link a div to the controller the controller function isn't found:

angular.js:13920 Error: [ng:areq] Argument 'menuCtrl' is not a function, got undefined


Here's how I link in the controller:

<div id="wrapper" class="row row-offcanvas row-offcanvas-left" ng-controller="menuCtrl" uib-collapse="showMenu" horizontal>

<div id="sidebar-wrapper" class="col-xs-6 col-sm-3 sidebar-offcanvas" ng-show="menuOpen" role="navigation">

<ul class="nav nav-pills nav-stacked">
<li><a href="#/view1">view1</a></li>
<li><a href="#/view2">view2</a></li>
</ul>

</div>

<div id="page-content-wrapper" class="col-xs-12 col-sm-9">

<div ng-view></div>

<div>Angular seed app: v<span app-version></span></div>

</div>

</div>


Here's the main.js:

/*global require, requirejs */

'use strict';

requirejs.config({
paths: {
'angular': ['../lib/angularjs/angular'],
'angular-route': ['../lib/angularjs/angular-route'],
'ui-bootstrap':['../lib/angular-ui-bootstrap/ui-bootstrap']
},
shim: {
'angular': {
exports : 'angular'
},
'angular-route': {
deps: ['angular'],
exports : 'angular'
},
'ui-bootstrap': {
deps: ['angular'],
exports: 'ui-bootstrap'
}
}
});

require(['angular', './controllers', './directives', './filters', './services', 'angular-route', "ui-bootstrap"],
function(angular, controllers) {

// Declare app level module which depends on filters, and services

angular.module('eprogram2', ['eprogram2.filters', 'eprogram2.services', 'eprogram2.directives', 'ngRoute']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: controllers.MyCtrl1});
$routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: controllers.MyCtrl2});
$routeProvider.otherwise({redirectTo: '/view1'});
}]);

angular.module('eprogram2', ['ui.bootstrap']);

angular.bootstrap(document, ['eprogram2']);


});


and the controller.js:

'use strict';

define(function() {

/* Controllers */

var controllers = {};

controllers.MyCtrl1 = function() {}
controllers.MyCtrl1.$inject = [];

controllers.MyCtrl2 = function() {}
controllers.MyCtrl2.$inject = [];

controllers.menuCtrl = function($scope, $window) {
$scope.menuOpen = false;

console.log("MenuCtrl");

// Detect if mobile portrait screen size
$scope.is_mobile = ($window.innerWidth <= 480);

if ($scope.isMobile) {
$scope.menuOpen = false;
console.log("mobile detected - close menu")
} else {
$scope.menuOpen = true;
console.log("not mobile - open menu")
}

}
controllers.menuCtrl.$inject = ['$scope', '$window'];

return controllers;

});


I've tried using the template project's controllers and mine but no go. The routing instructions find their controllers no problem in main.js, but the controllers don't seem to be exposed to the HTML page. I've tried:

eprogram2.controllers.menuCtrl
controllers.menuCtrl
eprogram2.menuCtrl

formats as well, but all return the same not a function, got undefined message. Any suggestions about what my boneheaded mistake is?

Answer

You have 2 declarations for module('eprogram2') .

You can only declare a module once.

Remove:

angular.module('eprogram2', ['ui.bootstrap']);

and add 'ui.bootstrap' dependency to the initial declaration.

On a side note it looks like the seed you are using is fairly old. I would suggest following John Papa's style guide and the rule of 1 and have one component per file. You will appreciate it in the long run.

The idea of grouping controllers into controller modules and directives into directive modules has long been superseded with grouping features into modules. They become a lot more portable that way

Comments