Controller in separate file throws error - angularjs

I am moving my controllers from one unique file containing my whole app to separate files and get that error : "Error: [ng:areq] Argument 'MainCtrl' is not a function, got undefined"
I used the setting method to define my app in app.js :
var app = angular.module('CMT', ['ui.router', 'angularCharts', 'uiSwitch']);
I then created a file MainCtrl.js with :
angular.module('CMT').controller('MainCtrl', [
'$scope', 'reviews', '$location',
function($scope, reviews, $location){
}]);
And I have included the files in index.html after including the angular source code :
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.js"></script>
<script src='library/d3.min.js' type='text/javascript'></script>
<script src='library/angular-charts.min.js' type='text/javascript'></script>
<script src="node_modules/angular-ui-switch/angular-ui-switch.min.js"></script>
<script src="app.js" type='text/javascript'></script>
<script src="MainCtrl.js" type='text/javascript'></script>
Any hint or solution ?

Try the following:
In your app.js, inject your MainCtrl.js, like:
var app = angular.module('CMT', ['ui.router', 'angularCharts', 'uiSwitch', 'CMT.MainCtrl']);
And in your MainCtrl.js:
angular.module('CMT.MainCtrl', [])
EDIT:
An AngularJS module is a container. In every Angularjs app, you have one "main" module, and typically many sub-modules. These sub-modules are useful for modularizing/separating your app into components, like controllers, services etc. Initially you had one main module, which also contained the code for your controller. When you decided to move your controller out of the main module, what you wanted to do was move it into a sub-module.
So there were two problems with what you did:
You named your controller module (which is your sub-module in this case) the same name 'CMT' as that of your app/main module. Your sub-modules need to have unique names, and it is good practice to use the . separator - see this Angular style guide.
You didn't "link" your controller module to your app module in an Angular way. Just adding the script to your html isn't enough. If you have a sub-module called CMT.MainCtrl, you need to inject it into your main CMT module.
Judging by your naming convention MainCtrl.js versus something like controllers.js, I'm guessing you're organising your code by feature, instead of by type? In any case, read Angular best practices for more info on Angular directory structure.

Specify all your services/controllers/filters/directives files before the app.js file
<script src="MainCtrl.js" type='text/javascript'></script>
<script src="app.js" type='text/javascript'></script>
Note: you don't need to care about these file orders if you bundle all your script files into single file

Related

How should I define the module to add controllers to it?

I've got my angular app setup something like this:
<div class="main" ng-app="myApp">
<div class="sub" ng-controller="sub1">
...
</div>
<div class="sub" ng-controller="sub2">
...
</div>
<div class="sub" ng-controller="sub3">
...
</div>
</div>
And the controllers each on different js file so the file structure is like:
Templates
-> home.html
Controllers
-> sub1Controller
-> sub2Controller
-> sub3Controller
In each controller file, I add the controller to the app by doing
ngApp.controller("sub1", function($scope){ ... });
And in the html file I linked the scripts.
After a few takes on getting the got undefined error, I found out that I am creating a new app on every directive, because to get the ngApp I used angular.module("myApp", []), unlike angular.module("myApp") that would retrieve the module. So basically my question is, where should I define the module? Since doing angular.module("myApp") won't work before angular.module("myApp", []) is invoked I can't use the one without the brackets always. Is defining the module on the containing page a bad practice? Is separating the controllers to different files instead of all in the same one a bad practice?
Separating controllers out into separate files is definitely a good idea, and I commend you for doing so. I'd recommend adding additional file above the controllers directory to define the angular module.
templates
-> home.html
js
->
angular_config.js
controllers
-> sub1Controller
-> sub2Controller
-> sub3Controller
There is nothing wrong with having all your controllers in the same file but for simplicity and future complexity reasons it is better to store each controller in a separate file.
A good solution may be to put all your controllers in controller folder(what you are currently doing )
the second thing is load another file that you can call app.js which will link all the controllers and other stuff together for example
in your app.js in the the js folder you can write :
window.onload = function(){
var app = angular.module('mymodal',[]);
app.controller('sub1Controller',function(){});
app.controller('sub2Controller',function(){});
app.controller('sub2Controller',function(){});
};
and then in your index.* file load js files in the following order
<script src="js/controllers/sub1Controller.js"></script>
<script src="js/controllers/sub2Controller.js"></script>
<script src="js/controllers/sub3Controller.js"></script>
<script src="js/app.js"></script>
By the way you can concatenate all your controllers files in one single file using task runner tools like grunt or gulp.

ui-boostrap $modal causes Error: [$injector:unpr]

I'm new to angularjs and ui-bootstrap 13 and need some help.
I'm getting a unresolved from thew angularjs injector and can't figure out why.
The module definition looks like this:
var app = angular.module('MobileCOP', [
"ngRoute",
"ngTouch",
"mobile-angular-ui",
"ui.bootstrap"]);
The controller looks like this:
app.controller('CDRserver',['$rootScope','$scope','$location','serverList','$modal',
function($rootScope, $scope, $location, serverList, $modal ){
All I need to do to cause the error is inject $modal into the controller. I don't reference the modal in the code, just adding the modal service to the controller causes the issue. When the service is removed the error stops.
I'm assuming I'm missing something obvious.
Edit" As per request showing the controller assignment into the html:
.when('/cdrquery', {
templateUrl: '/MobileCOP/tmpl/CDRlist.html',
controller: 'CDRList'
})
Error:
[$injector:unpr] http://errors.angularjs.org/1.2.15/$injector/unpr?p0=%24templateRequestProvider%20%3C-%20%24templateRequest%20%3C-%20%24modal
z/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:6:450
Zb/l.$injector<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:34:1
c#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:33:83
Zb/q.$injector<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:35:57
c#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:33:83
d#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:33:300
Zb/q.$injector<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:35:75
c#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:33:83
d#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:33:300
f/<.instantiate#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:33:464
Md/this.$get</<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:65:484
z/<.link#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js:7:248
J#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:52:492
h#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:46:28
ba/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:45:200
Z/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:46:431
q#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:50:162
v#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js:6:357
Wd/this.$get</h.prototype.$broadcast#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:110:279
l/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js:11:177
ve/e/l.promise.then/H#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:96:513
ve/e/l.promise.then/H#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:96:513
ve/f/<.then/<#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:98:173
Wd/this.$get</h.prototype.$eval#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:108:36
Wd/this.$get</h.prototype.$digest#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:105:323
Wd/this.$get</h.prototype.$apply#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:108:368
g#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:71:118
C#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:75:241
re/</y.onreadystatechange#http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js:76:280
<ng-view class="app-content ng-scope">
Loading scripts code:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-route.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular-touch.min.js"></script>
<script src="/MobileCOP/libs/mobile-angular-ui.min.js"></script>
<script src="/MobileCOP/libs/ui-bootstrap-0.13.0.min.js"></script>
<!-- Required to use $touch, $swipe, $drag and $translate services -->
<script src="/MobileCOP/libs/mobile-angular-ui.gestures.min.js"></script>
<script src="/MobileCOP/libs/xml2json.min.js"></script>
It appears that you are not using a template enabled version of the ui-bootstrap libraries. From the ui-bootstrap FAQ:
The dist files with the -tpls- in their name come with the templates bundled inside $templateCache . You can check how this bundling works by inspecting this file. The important point here is that templates are part of the distribution file so you don't need to download them separately. Also, those templates are pre-loaded with JS file so a browser won't request them on run-time.
bottom line, for template enabled modules like modal to work, you need to be loading the script ui-bootstrap-tpls-0.13.0.js.
The error you are getting is coming from the templateRequestProvider when it looks for a template for $modal that isn't in the template cache.
OK cleared up the issue.. ui-bootstrap-tpls-0.13.0.js is incompatible with angularjs 1.2.15. Upgraded to 1.3.14, the error is gone.

AngularJS loading modules

I'm having a really hard time trying to make modules working on an app I'm building.
This is the main file
main.js
'use strict';
angular.module('clientPortalPublic',[
'ngCookies',
'ngResource',
'ngAnimate',
'clientPortalPublic.components'
]);
angular.module('clientPortalPublic.components',[]);
And I have another file switch-login-effect.js
'use strict';
angular.module('clientPortalPublic.components').directive('switchLoginEffect',['$timeout', function($timeout){
//Content removed for clarification
}]);
The order that those files are being loaded is:
<script type="application/javascript" src="public/components/switch-login-effect.js"></script>
<script type="application/javascript" src="public/main.js"></script>
I know the switch-login-effect.js should be loaded later, since is requiring the main module, but it's being loaded dynamically and I don't control the order. BUT using manual bootstrapping shouldn't angular deal with it?
This is how I'm bootstrapping it
angular.element(document).ready(function() {
angular.bootstrap(document, ['clientPortalPublic']);
});
If I run the code above I get:
Error: [$injector:nomod] Module 'clientPortalPublic.components' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Thanks!
You are declaring a directive on a non-existant module when switch-login-effect.js loads first. It looks like you are trying to dynamically control what elements are included in the clientPortalPublic.components module simply by adding or removing scripts, but I don't think angular's dependencies are set up for that. A main reason to have those dependencies is to know exactly what you are getting.
The clientPortalPublic.components module should be defined in one script file if possible. If you have various components you can create different modules for each, but the definition of your application module should know what it is getting by the dependencies it requires. That would cause debugging headaches for one reason, "Why is my directive not working? I'm loading the components module..." (but you missed a script file you have no way to know that you need)
I really don't advise creating your app this way, but if you are dead-set you could catch the error and create the module at the start of each individual component file (and in your main.js in case you don't actually have any components but still want to require the module) so it doesn't matter which one is loaded first:
try {
angular.module('clientPortalPublic.components');
} catch (err) {
angular.module('clientPortalPublic.components',[]);
}
Or more simply just uses javascript to see if it's been executed:
var componentsModule = componentsModule ||
angular.module('clientPortalPublic.components',[]);
After reading some angular good practices and paying more attention to angular seed, I have it working.
THe thing is that they recommend to do the following when you have an structure similar to:
app/
app/components
app/components/component1
app/components/component2
app.js => angular.module('main',['main.components']);
app/components/components.js => angular.module('main.components',['main.components.component1', 'main.components.component2']);
app/components/component1.js => angular.module('main.components.component1',[]);
app/components/component2.js => angular.module('main.components.component2',[]);
Having that structure make sense and works perfectly.
:)

How to Modularize AngularJS app(folder structure)?

Assume I am going to start new AngularJs app with 3 modules:
login
payment
enquiry
I want to load payment module with login details similarly for enquiry, how can we achieve this?
I will have 1 login screen which will call server and check for login, after that server will respond with some parameter which I will use in payment and enquiry module.
If I load login module with other 2 modules:
var myModule = angular.module('myApp', ['payment', 'enquiry']);
It will load both modules on login (I am not sure), but i want like this:
var myModule = angular.module('myApp', ['login']);
// i.e for payment:
var myModule = angular.module('payment', ['login']);
// and for enquiry:
var myModule = angular.module('enquiry', ['login']);
Only login should be loaded. I will use login parameters here.
Any suggestions?
Firstly, you are not "loading" the modules with that syntax, only making sure that they are initialized in the right order. Loading the modules is done by including them in your index.html page (or by using requirejs or similar, but that will make it a completely different beast).
Assuming you are building a SPA (Single Page Application) you will only have one main module, and that will have to reference all other modules you want to use, directly or indirectly. So if you do it the way you want, you will never be able to access payment or enquiry. So you should do:
in app.js
var myModule = angular.module('myApp', ['payment', 'enquiry']);
in payment.js
var myModule = angular.module('payment', ['login']);
in enquiry.js
var myModule = angular.module('enquiry', ['login']);
in login.js
var myModule = angular.module('login', []);
in index.html
<html ng-app="myApp">
...
<script src="app.js"></script>
<script src="payment.js"></script>
<script src="enquiry.js"></script>
<script src="login.js"></script>
...
</html>
And remember since you will be including the JavaScript code for all these in the index.html you will "load" all the code always no matter how you define your modules, you will also only have one module "bound" to your application, and that module will have to have access to all other modules you are including.
If you however want to do lazy loading (load resources (modules, controllers, filters, providers etc.) when you need them that is a completely different beast and will require a lot of extra code all over your applications as well as some hackish ways of using angularjs, unless you use something, http://marcoslin.github.io/angularAMD/#/home. There is also a good discussion on if you should or should not use lazy loading here: Does it make sense to use Require.js with Angular.js?

AngularJS - Directive not recognizing controller

If I have a directive and a controller in the same file:
var app = angular.module('app.navigation', []);
app.controller('NavItemCtrl', [ ....])
app.directive('navItem', [
'ribbon', '$window', function (ribbon, $window) {
return {
require: ['^navigation', '^?navGroup'],
restrict: 'AE',
controller: 'NavItemCtrl',
...
}])
Everything is fine, but if I move the controller code to a different file, because the current file is becoming too clutered, using the same module, and referencing the new controller file in my index page, the directive screams
p0=NavItemCtrl&p1=not aNaNunction got undefined
My index page is like this:
<html>
<body>
....
<script app.js ...>
<script new controller file path .... >
<script original directive file path .... >
....
</body>
</html>
What am I missing here?
[Solution] Delta is right, I figured it out:
For good housing keeping, I think it may be wise to have one JS file, listed as a dependency in the main app.js, that instantiates all the modules you will use, assuming your project is becoming large, and then reuse that instantiate w/o having any dependencies.
As example:
(1) Main App:
angular.module('MainApp', ['ngRoute', 'ngAnimate', 'app.SubApp1', 'app.SubApp2', 'app.SubApp3' ...]
(2) Then as a repository, if you will, create a new js file, say repositoryApp.js, instantiating these sub apps, making sure that this file is referenced before all other files that will use these sub app modules:
angular.module('app.SubApp1', [xxx]);
angular.module('app.SubApp2', [xxx]);
angular.module('app.SubApp3', [xxx]);
(3) Then when creating a series of directives, controllers, or whatever pertaining to a particular sub app, merely reference that sub app in the respective file as:
angular.module('app.SubApp1').controller('foo') .....
angular.module('app.SubApp1').directive('bar') .....
Without the dependency brackets as that is what threw the error for me.
in your directive are you getting you app like this
var app = angular.module('app.navigation');
if you put the brackets after it like your first example you will just be replacing what you have currently instead of getting it.
This get a new module
var app = angular.module('app.navigation', []);
This gets an existing modules.
var app = angular.module('app.navigation');
Notice the exclusion of the brackets in the second example.

Resources