How to create separate AngularJS controller files?
Solution 1
File one:
angular.module('myApp.controllers', []);
File two:
angular.module('myApp.controllers').controller('Ctrl1', ['$scope', '$http', function($scope, $http){
}]);
File three:
angular.module('myApp.controllers').controller('Ctrl2', ['$scope', '$http', function($scope, $http){
}]);
Include in that order. I recommend 3 files so the module declaration is on its own.
As for folder structure there are many many many opinions on the subject, but these two are pretty good
https://github.com/angular/angular-seed
http://briantford.com/blog/huuuuuge-angular-apps.html
Solution 2
Using the angular.module API with an array at the end will tell angular to create a new module:
myApp.js
// It is like saying "create a new module"
angular.module('myApp.controllers', []); // Notice the empty array at the end here
Using it without the array is actually a getter function. So to seperate your controllers, you can do:
Ctrl1.js
// It is just like saying "get this module and create a controller"
angular.module('myApp.controllers').controller('Ctrlr1', ['$scope', '$http', function($scope, $http) {}]);
Ctrl2.js
angular.module('myApp.controllers').controller('Ctrlr2', ['$scope', '$http', function($scope, $http) {}]);
During your javascript imports, just make sure myApp.js is after AngularJS but before any controllers / services / etc...otherwise angular won't be able to initialize your controllers.
Solution 3
Although both answers are technically correct, I want to introduce a different syntax choice for this answer. This imho makes it easier to read what's going on with injection, differentiate between etc.
File One
// Create the module that deals with controllers
angular.module('myApp.controllers', []);
File Two
// Here we get the module we created in file one
angular.module('myApp.controllers')
// We are adding a function called Ctrl1
// to the module we got in the line above
.controller('Ctrl1', Ctrl1);
// Inject my dependencies
Ctrl1.$inject = ['$scope', '$http'];
// Now create our controller function with all necessary logic
function Ctrl1($scope, $http) {
// Logic here
}
File Three
// Here we get the module we created in file one
angular.module('myApp.controllers')
// We are adding a function called Ctrl2
// to the module we got in the line above
.controller('Ctrl2', Ctrl2);
// Inject my dependencies
Ctrl2.$inject = ['$scope', '$http'];
// Now create our controller function with all necessary logic
function Ctrl2($scope, $http) {
// Logic here
}
Solution 4
What about this solution? Modules and Controllers in Files (at the end of the page) It works with multiple controllers, directives and so on:
app.js
var app = angular.module("myApp", ['deps']);
myCtrl.js
app.controller("myCtrl", function($scope) { ..});
html
<script src="app.js"></script>
<script src="myCtrl.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
Google has also a Best Practice Recommendations for Angular App Structure I really like to group by context. Not all the html in one folder, but for example all files for login (html, css, app.js,controller.js and so on). So if I work on a module, all the directives are easier to find.
Solution 5
For brevity, here's an ES2015 sample that doesn't rely on global variables
// controllers/example-controller.js
export const ExampleControllerName = "ExampleController"
export const ExampleController = ($scope) => {
// something...
}
// controllers/another-controller.js
export const AnotherControllerName = "AnotherController"
export const AnotherController = ($scope) => {
// functionality...
}
// app.js
import angular from "angular";
import {
ExampleControllerName,
ExampleController
} = "./controllers/example-controller";
import {
AnotherControllerName,
AnotherController
} = "./controllers/another-controller";
angular.module("myApp", [/* deps */])
.controller(ExampleControllerName, ExampleController)
.controller(AnotherControllerName, AnotherController)
Beebunny
Updated on March 24, 2020Comments
-
Beebunny about 4 years
I have all of my AngularJS controllers in one file, controllers.js. This file is structured as follows:
angular.module('myApp.controllers', []) .controller('Ctrl1', ['$scope', '$http', function($scope, $http) { }]) .controller('Ctrl2', ['$scope', '$http', function($scope, $http) } }])
What I'd like to do is put Ctrl1 and Ctrl2 into separate files. I would then include both files in my index.html, but how should that be structured? I tried doing some thing like this and it throws an error in the web browser console saying it can't find my controllers. Any hints?
I searched StackOverflow and found this similar question - however, this syntax is using a different framework (CoffeeScript) on top of Angular, and so I haven't been able to follow.
-
Andrew about 10 yearsIf the OP indicated confusion about CoffeeScript syntax, maybe it would be best not to use it in your answer?
-
Andrew about 10 years@Fresheyeball, cool. I realize the question has come and gone, but it confused me for a brief second, so maybe this will help out future viewers.
-
Fresheyeball about 10 years@Andrew imho future help and making a record of solutions is what SO is really all about, not extemporaneous q and a.
-
Ruslan Ismagilov about 10 yearsFile one:
var appCtrl = angular.module('myApp.controllers', []);
File two:appCtrl.controller('Ctrlr1');
File three:appCtrl.controller('Ctrlr2');
-
Fresheyeball about 10 years@RuslanIsmagilov your
appCtrl
is a globalwindow.appCtrl
. That is not a good practice. -
vipin almost 10 yearswhere should i write my dependencies. var myapp = angular.module('demo', ['ngRoute','ngCookies','ui.bootstrap','nvd3ChartDirectives','ui-rangeSlider','textAngular','angularTreeview']);
-
Jimmy Au almost 10 years@vipin just like what you've typed, but make sure it's above any controllers, services, etc. Technically you don't need to declare var myapp = ...; because angular will store it for you.
-
Deoxyseia over 9 years@Fresheyeball, the problem of this approach is which the order of import in the index.html is important, otherwise, Angular emit error.
-
Fresheyeball over 9 years@Deoxyseia so put your files in order. Whats the problem?
-
Deoxyseia over 9 yearsThe problem is which many yeoman generator import automatically the js files, without specific order. I think which a better solutions is define all items as modules. By example scotch.io/tutorials/javascript/….
-
Fresheyeball over 9 yearsThat sounds like a problem with yeoman. It's an anti-pattern to alter code structure because of problems introduced by tooling.
-
hendryau over 9 yearswhy use 'myApp.controllers' instead of just 'myApp' as the module name?
-
Fresheyeball over 9 years@hendryau, well I was working with the module name present in the OP. That said, some feel that its better organizationally, to have multiple name-spaced modules, rather than a central app module.
-
sham over 9 years@Fresheyeball, Just as you mentioned I have created each controller in a seperate js file. All the controllers are placed in a Controller folder at the root. When my views are loaded the corresponding controllers are not attached. Each view is contained in a <div ng-controller="loginController"> ........</div>. Am I missing something?
-
Fresheyeball over 9 years@sham, I would need to see the structure of your html. The problem you are having doesn't sound like it has anything to do with the controllers being in separate files, but rather instantiating with your views. Feel free to post a new question and paste a link to it here. I will come help.
-
sham over 9 years@Fresheyeball, this is the link stackoverflow.com/questions/28727173/…
-
Jim Aho about 9 yearsIn this case, what would be the name of File one? I've not found a good naming-convention.
-
Fresheyeball about 9 yearsI've been calling an analog to
File one
,modules.js
, and using this file only to declare modules and manage dependencies. -
QViet almost 9 yearsi use this code but still cannot load my controller ? it throw error: Error: [ng:areq] Argument 'ProductCtrl' is not a function, got undefined.
-
mrwaim almost 9 yearsInteresting, it does keep me from going to multiple files to register a controller
-
Brendan W almost 9 yearsthis is really bad practice
-
Alaksandar Jesus Gene almost 9 yearsI see a lots of coding like this. What is the advantage? of having $inject and a function seperate.
-
Robert Johnstone over 8 yearsHow does this work if I have
<html ng-app="..." ng-controller="Ctrl1">
? -
Fresheyeball over 8 yearsThis method should not be effected by representation in the dom.
-
Pablo over 8 yearsHow to avoid load all the controllers files in the master page?
-
Fresheyeball over 8 years@Pablo 2 choices: use a lazy loader like
require
to load as needed, concat them into one file using a build tool likegulp
. -
thank_you over 8 yearsI believe it makes the code easier to read. I know what exactly is being injected. Think of it as a "separation of concerns" on a line-by-line basis.
-
Sinaesthetic over 8 years@JimmyAu Where does Ctrl1.js and Ctrl2.js get loaded so that the page can use it? I have myApp.js loaded just after angular, but the page can't find the controllers. Do I have to explicitly add them as a script on the view that needs it? Or do I still have to include every controller file on every page?
-
Devner over 8 years@Kim Jong Un You will see that error if you don't add/concatenate the controller to the module that you created. So it will work if you use the following syntax:
angular.module('myApp').controller('ProductCtrl', ['$scope', '$http', function($scope, $http){ //Your ProductCtrl code goes here }]);
-
Jim B. over 8 yearsThanks for clarifying why only the first call needs [].
-
Juan Carlos Oropeza over 7 yearsCan you do the same to split
'Ctrl1'
in two separated files if that controller is becoming to big? -
Fresheyeball over 7 years@JuanCarlosOropeza if your controller is getting to big, I advise you to revisit your application design. Controllers should not be that big.
-
Antti Pihlaja over 7 yearsYou could save quite bit of typing if you used named functions.. they have handy property
name
.. so you can simply useExampleCtrl.name
instead of dupl.. triplicating it. -
rfornal over 7 yearsCode like this not only produces more readable code, is much easier to debug, and reduces the amount of nested callback code (see github.com/johnpapa/angular-styleguide/blob/master/a1/…)
-
Dan Chase about 7 yearsIf I could +1 this 1000 times I would - bravo!
-
FreeKrishna almost 7 yearsWhere should the code for
app.config
and app.run` should go? the app.js or the controller.js file? or something else? my first app file contains onlyvar app = angular.module("test", ["ngRoute"]);
. Any help is appreciated. -
Mawg says reinstate Monica over 6 years@Brendan, simply stating that something is bad practise is better than nothing - but not much. Tell us why it is bad practise will help others.
-
negrotico19 about 4 yearsThis example guided me enough: github.com/angular/angular-seed First it failed because I forgot to add <script scr="myfile1.js"></script> into index.html
-
Darius.V over 3 yearsI cannot make it work. plnkr.co/edit/… - Module 'myApp' is not available!