How to create separate AngularJS controller files?

215,545

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)
Share:
215,545
Beebunny
Author by

Beebunny

Updated on March 24, 2020

Comments

  • Beebunny
    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.


    AngularJS: How do I create controllers in multiple files

  • Andrew
    Andrew about 10 years
    If the OP indicated confusion about CoffeeScript syntax, maybe it would be best not to use it in your answer?
  • Andrew
    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
    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
    Ruslan Ismagilov about 10 years
    File one: var appCtrl = angular.module('myApp.controllers', []);File two: appCtrl.controller('Ctrlr1'); File three: appCtrl.controller('Ctrlr2');
  • Fresheyeball
    Fresheyeball about 10 years
    @RuslanIsmagilov your appCtrl is a global window.appCtrl. That is not a good practice.
  • vipin
    vipin almost 10 years
    where should i write my dependencies. var myapp = angular.module('demo', ['ngRoute','ngCookies','ui.bootstrap','nvd3ChartDirectives',‌​'ui-rangeSlider','te‌​xtAngular','angularT‌​reeview']);
  • Jimmy Au
    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
    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
    Fresheyeball over 9 years
    @Deoxyseia so put your files in order. Whats the problem?
  • Deoxyseia
    Deoxyseia over 9 years
    The 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
    Fresheyeball over 9 years
    That sounds like a problem with yeoman. It's an anti-pattern to alter code structure because of problems introduced by tooling.
  • hendryau
    hendryau over 9 years
    why use 'myApp.controllers' instead of just 'myApp' as the module name?
  • Fresheyeball
    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
    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
    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
    sham over 9 years
    @Fresheyeball, this is the link stackoverflow.com/questions/28727173/…
  • Jim Aho
    Jim Aho about 9 years
    In this case, what would be the name of File one? I've not found a good naming-convention.
  • Fresheyeball
    Fresheyeball about 9 years
    I've been calling an analog to File one, modules.js, and using this file only to declare modules and manage dependencies.
  • QViet
    QViet almost 9 years
    i use this code but still cannot load my controller ? it throw error: Error: [ng:areq] Argument 'ProductCtrl' is not a function, got undefined.
  • mrwaim
    mrwaim almost 9 years
    Interesting, it does keep me from going to multiple files to register a controller
  • Brendan W
    Brendan W almost 9 years
    this is really bad practice
  • Alaksandar Jesus Gene
    Alaksandar Jesus Gene almost 9 years
    I see a lots of coding like this. What is the advantage? of having $inject and a function seperate.
  • Robert Johnstone
    Robert Johnstone over 8 years
    How does this work if I have <html ng-app="..." ng-controller="Ctrl1">?
  • Fresheyeball
    Fresheyeball over 8 years
    This method should not be effected by representation in the dom.
  • Pablo
    Pablo over 8 years
    How to avoid load all the controllers files in the master page?
  • Fresheyeball
    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 like gulp.
  • thank_you
    thank_you over 8 years
    I 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
    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
    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.
    Jim B. over 8 years
    Thanks for clarifying why only the first call needs [].
  • Juan Carlos Oropeza
    Juan Carlos Oropeza over 7 years
    Can you do the same to split 'Ctrl1' in two separated files if that controller is becoming to big?
  • Fresheyeball
    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
    Antti Pihlaja over 7 years
    You could save quite bit of typing if you used named functions.. they have handy property name.. so you can simply use ExampleCtrl.name instead of dupl.. triplicating it.
  • rfornal
    rfornal over 7 years
    Code 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
    Dan Chase about 7 years
    If I could +1 this 1000 times I would - bravo!
  • FreeKrishna
    FreeKrishna almost 7 years
    Where 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 only var app = angular.module("test", ["ngRoute"]); . Any help is appreciated.
  • Mawg says reinstate Monica
    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
    negrotico19 about 4 years
    This 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
    Darius.V over 3 years
    I cannot make it work. plnkr.co/edit/… - Module 'myApp' is not available!